Peter Kronenberg
Peter Kronenberg

Reputation: 1296

Adding custom arguments to Jackson deserializer

I have a custom deserializer. But I want to be able to pass additional arguments. For example

@JsonDeserialize(using=CustomDeserializer.class, customParm=value)
MyObject obj;

How can I pass in my custom parameter on the annotation?

Upvotes: 5

Views: 6093

Answers (2)

ÖMER TAŞCI
ÖMER TAŞCI

Reputation: 566

According to previous solution I create my custom date deserializer.And it works for me.

First create your annotaition.

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomDateFormat {
    String customDateFormat();
}

Second create your serializer class.

public class CustomDateDeserializer extends StdDeserializer<DateTime> implements ContextualDeserializer {

private SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
private String customDateFormat = null;

public CustomDateDeserializer() {
    this(null);
}

public CustomDateDeserializer(Class<?> vc) {
    super(vc);
}
public CustomDateDeserializer(Class<?> vc, String customDateFormat) {
    super(vc);
    this.customDateFormat = customDateFormat;
}

@Override
public DateTime deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException {
    String date = jsonparser.getText();
    try {

        if (!Util.nullToBosluk(date).equals(""))
            return new DateTime(getDateFormat(this.customDateFormat).parse(date));
    } catch (ParseException e) {
        throw new RuntimeException(e);
    }
    return null;
 }

@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
        throws JsonMappingException {
    CustomDateFormat customDateFormatAnn = property.getAnnotation(CustomDateFormat.class);
    if (customDateFormatAnn != null) {
        String customParam = customDateFormatAnn.customDateFormat();
        return new CustomDateDeserializer(this._valueClass, customParam);
    }
    return this;
 }

private DateFormat getDateFormat(String customDateFormat) {
    if (StringUtils.isNotBlank(customDateFormat))
        return new SimpleDateFormat(customDateFormat);
    else
        return this.formatter;
 }
}

Finally use your new annotation in your code.

...
@JsonDeserialize(using = CustomDateDeserializer.class)
DateTime invoiceDate;
@JsonDeserialize(using = CustomDateDeserializer.class)
@CustomDateFormat(customDateFormat = "dd/MM/yyyy HH:mm")
DateTime createDate;
...

Upvotes: 1

Thomas Fritsch
Thomas Fritsch

Reputation: 10127

You cannot add your own parameters to @JsonDeserialize, because you can't alter Jackson's implementation of this annotation.

However, you can achieve your goal in a slightly different way. You can invent your own annotation (let's call it @MyAnnotation) and use that alongside with the @JsonDeserialize annotation on your property:

@JsonDeserialize(using = CustomDeserializer.class)
@MyAnnotation(customParm = "value")
private MyObject obj;

The implementation of the annotation is pretty straight-forward. The following example annotation just defines a single String parameter.

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String customParm();
}

Then you can access the parameters of @MyAnnotation from within your deserializer as follows.

  • As usual your deserializer needs to implement the deserialize method where you do the actual deserialization of the property.

  • Besides that your deserializer needs to implement the ContextualDeserializer interface and implement the createContextual method. Here you configure your deserializer (by getting the customParm from @MyAnnotation). Jackson will call this method before the actual deserialization.

public class CustomDeserializer extends StdDeserializer<MyObject> implements ContextualDeserializer {

    private String customParm = null;

    public CustomDeserializer() {
        super(MyObject.class);
    }

    public CustomDeserializer(String customParm) {
        super(MyObject.class);
        this.customParm = customParm;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
            throws JsonMappingException {
        MyAnnotation myAnnotation = property.getAnnotation(MyAnnotation.class);
        if (myAnnotation != null) {
            String customParm = myAnnotation.customParm();
            // return a new instance, so that different properties will not share the same deserializer instance
            return new CustomDeserializer(customParm);
        }
        return this;
    }

    @Override
    public MyObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        // do your deserialization (using customParm)
        return ...;
    }
}

Upvotes: 8

Related Questions