Spring 3.2 and Jackson 2: add custom object mapper

2020-02-09 08:30发布

问题:

I'm developing a REST webservice in spring MVC. I need to change how jackson 2 serialize mongodb objectids. I'm not sure of what to do because I found partial documentation for jackson 2, what I did is to create a custom serializer:

public class ObjectIdSerializer extends JsonSerializer<ObjectId> {


    @Override
    public void serialize(ObjectId value, JsonGenerator jsonGen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        jsonGen.writeString(value.toString());
    }
}

Create a ObjectMapper

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        SimpleModule module = new SimpleModule("ObjectIdmodule");
        module.addSerializer(ObjectId.class, new ObjectIdSerializer());
        this.registerModule(module);
    }

}

and then register the mapper

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="my.package.CustomObjectMapper"></bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

My CustomConverter is never called. I think the CustomObjectMapper definition is wrong,I adapted it from some code for jackson 1.x

In my controllers I'm using @ResponseBody. Where am I doing wrong? Thanks

回答1:

You should annotate corresponding model field with @JsonSerialize annontation. In your case it may be:

public class MyMongoModel{
   @JsonSerialize(using=ObjectIdSerializer.class)
   private ObjectId id;
}

But in my opinion, it should better don't use entity models as VOs. Better way is to have different models and map between them. You can find my example project here (I used date serialization with Spring 3 and Jackson 2 as example).



回答2:

How I would do this is:

Create an annotation to declare your custom serializers:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMessageConverter{
}

Set up component scan for this in your mvcconfiguration file

<context:include-filter expression="package.package.MyMessageConverter"
            type="annotation" />

and create a class that implements HttpMessageConverter<T>.

@MyMessageConverter
public MyConverter implements HttpMessageConverter<T>{
//do everything that's required for conversion.
}

Create a class that extends AnnotationMethodHandlerAdapter implements InitializingBean.

    public MyAnnotationHandler extends AnnotationMethodHandlerAdapter implements InitializingBean{
    //Do the stuffs you need to configure the converters
    //Scan for your beans that have your specific annotation
    //get the list of already registered message converters
    //I think the list may be immutable. So, create a new list, including all of the currently configured message converters and add your own. 
    //Then, set the list back into the "setMessageConverters" method.
    }

I believe this is everything that is required for your goal.

Cheers.



回答3:

There is no need to create object mapper. Add jackson-core-2.0.0.jar and jackson-annotations-2.0.0.jar to your project.

Now, add the following lines of code to your controller while handing the service:

@RequestMapping(value = "students", method = RequestMethod.POST, headers = "Accept=application/json", consumes = "application/json")

public HashMap<String, String> postStudentForm(
            @RequestBody Student student, HttpServletResponse response)

Do not miss any of the annotations.