Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java spring MappingJacksonJsonView not doing toString on mongodb ObjectId

I am using the MappingJacksonJsonView in my SpringMVC application to render JSON from my controllers. I want the ObjectId from my object to render as .toString but instead it serializes the ObjectId into its parts. It works just fine in my Velocity/JSP pages:

Velocity:
    $thing.id
Produces:
    4f1d77bb3a13870ff0783c25


Json:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'json',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    thing: {id:{time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739},…}
        id: {time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739}
            inc: -260555739
            machine: 974358287
            new: false
            time: 1327331259000
            timeSecond: 1327331259
        name: "Stack Overflow"


XML:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'xml',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    <com.place.model.Thing>
        <id>
            <__time>1327331259</__time>
            <__machine>974358287</__machine>
            <__inc>-260555739</__inc>
            <__new>false</__new>
        </id>
        <name>Stack Overflow</name>
    </com.place.model.Thing>

Is there a way to stop MappingJacksonJsonView from getting that much information out of the ObjectId? I just want the .toString() method, not all the details.

Thanks.

Adding the Spring config:

@Configuration
@EnableWebMvc
public class MyConfiguration {

    @Bean(name = "viewResolver")
    public ContentNegotiatingViewResolver viewResolver() {
        ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver();
        contentNegotiatingViewResolver.setOrder(1);
        contentNegotiatingViewResolver.setFavorPathExtension(true);
        contentNegotiatingViewResolver.setFavorParameter(true);
        contentNegotiatingViewResolver.setIgnoreAcceptHeader(false);
        Map<String, String> mediaTypes = new HashMap<String, String>();
        mediaTypes.put("json", "application/x-json");
        mediaTypes.put("json", "text/json");
        mediaTypes.put("json", "text/x-json");
        mediaTypes.put("json", "application/json");
        mediaTypes.put("xml", "text/xml");
        mediaTypes.put("xml", "application/xml");
        contentNegotiatingViewResolver.setMediaTypes(mediaTypes);
        List<View> defaultViews = new ArrayList<View>();
        defaultViews.add(xmlView());
        defaultViews.add(jsonView());
        contentNegotiatingViewResolver.setDefaultViews(defaultViews);
        return contentNegotiatingViewResolver;
    }

    @Bean(name = "xStreamMarshaller")
    public XStreamMarshaller xStreamMarshaller() {
        return new XStreamMarshaller();
    }

    @Bean(name = "xmlView")
    public MarshallingView xmlView() {
        MarshallingView marshallingView = new MarshallingView(xStreamMarshaller());
        marshallingView.setContentType("application/xml");
        return marshallingView;
    }

    @Bean(name = "jsonView")
    public MappingJacksonJsonView jsonView() {
        MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
        mappingJacksonJsonView.setContentType("application/json");
        return mappingJacksonJsonView;
    }
}

And my controller:

@Controller
@RequestMapping(value = { "/things" })
public class ThingController {

    @Autowired
    private ThingRepository thingRepository;

    @RequestMapping(value = { "/show/{thingId}" }, method = RequestMethod.GET)
    public String show(@PathVariable ObjectId thingId, Model model) {
        model.addAttribute("thing", thingRepository.findOne(thingId));
        return "things/show";
    }
}
like image 678
sbzoom Avatar asked Nov 04 '22 06:11

sbzoom


2 Answers

By default Jackson provides the serialization of Object received. ObjectId returns the Object therefor its attributes are visible after conversion to JSON. You need to specify the type of serialization required, Here in this case it is string. Thing entity class which is used to create ThingRepository will look like this to get this done:

public class Thing {
    @Id
    @JsonSerialize(using= ToStringSerializer.class)
    ObjectId id;

    String name;
}

Here make a note of added anotation @JsonSerialize(using= ToStringSerializer.class) which instructs to serialize the ObjectID to String.

like image 173
Kapil Bhagchandani Avatar answered Nov 07 '22 22:11

Kapil Bhagchandani


If you're using autowired instance of the auto configured mapper in Spring Boot, you can just add this customizer bean:

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    return builder -> builder.serializerByType(ObjectId.class, ToStringSerializer.instance);
}

Relevant imports:

import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.bson.types.ObjectId;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;

And then this will reflect anywhere the autowired mapper is used, for example:

@Service
public class MyService {
    private final ObjectMapper objectMapper;
    private final MongoTemplate mongoTemplate;

    @Autowired
    public MyService(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public String getJsonForMongoCommand(Document document) {
        return objectMapper.writeValueAsString(mongoTemplate.executeCommand(document));
    }
}

Or in this specific case (untested, might be unnecessary):

@Bean(name = "jsonView")
public MappingJacksonJsonView jsonView(ObjectMapper objectMapper) {
    final MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
    mappingJacksonJsonView.setContentType("application/json");
    mappingJacksonJsonView.setObjectMapper(objectMapper);
    return mappingJacksonJsonView;
}
like image 40
aksh1618 Avatar answered Nov 07 '22 21:11

aksh1618