Using a delegating deserializer with StdValueInstantiator

1,753 views
Skip to first unread message

Steve Bread

unread,
Sep 11, 2014, 8:15:37 PM9/11/14
to jackso...@googlegroups.com
Hi, I'm using a delegating deserializer with java.util.Date as the delegate type and my class 'CustomDate' as the target type. I want to apply this deserializer to a constructor argument in conjunction with a ValueInstantiator. I got it to work but I would like to know if there is a simpler way.

Delegating deserializer with java.util.Date as delegate type:
   public class CustomDateDeserializer extends StdDelegatingDeserializer<CustomDate>
   
{
     
public CustomDateDeserializer() {
         
super(new StdConverter<Date, CustomDate>() { ... });
     
}
     
     
public CustomDateDeserializer(Converter<?, CustomDate> converter,
                                   
JavaType delegateType,
                                   
JsonDeserializer<?> delegateDeserializer) { ... }
     
}
     
// other content omitted
   
}

POJO:
   @JsonValueInstantiator(value = TestInstantiator.class)
   
public class Test{
     
public Test(CustomDate customDate) {
     
}
     
// rest omitted
   
}

ValueInstantiator:
   public class TestInstantiator extends StdValueInstantiator
   
{
     
public boolean canCreateFromObjectWith() {
         
return true;
     
}

     
public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig config) {
         
CreatorProperty customDate = new CreatorProperty(new PropertyName("customDate"),
                                            config
.constructType(CustomDate.class), null, null,
                                           
null, null, 0, null, PropertyMetadata.STD_REQUIRED)
                                     
.withValueDeserializer(new CustomDateDeserializer());
         
return new CreatorProperty[] { customDate };
     
}

     
@Override
     
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) throws IOException, JsonProcessingException {
         
return new Test((CustomDate) args[0]);
     
}
   
}



Creating a Test instance fails with a NPE because the values for _delegateType and _delegateDeserializer in StdDelegatingDeserializer are null. These values are set by Jackson when deserializing a property of type CustomDate but are not set automatically when deserializing the constructor argument.
    
To resolve this, I have to use a fully initialized delegating deserializer in TestInstantiator
      new CustomDateDeserializer(new StdConverter<Date, CustomDate>() { ... },
                                 config
.constructType(Date.class),
                                 
new DateDeserializers.DateDeserializer());



Is this the correct way to do it or is there way to set up the CreatorProperty such that Jackson will set the delegateType and delegateDeserializer as it does for properties?

I set up a module with
   addDeserializer(CustomDate.class, new CustomDateDeserializer());
but Jackson does not associate the constructor argument with the custom deserializer and that's why I have to specify the deserializer explicitly for CreatorProperty.

Thanks.

Tatu Saloranta

unread,
Sep 11, 2014, 10:00:35 PM9/11/14
to jackso...@googlegroups.com
Actually you should not have to use ValueInstatiator here; custom deserializer should be used just fine for anything declared as CustomDate. So defined constructor like so:

  @JsonCreator
  Test(@JsonProperty("customDate") CustomDate d) {
       ...
  }

should work. If not, you could file an issue, preferably with a simplified unit test / code sample to reproduce.

As to delegating deserializer code seems fine, but you could also use annotations on CustomDate type, like so:

@JsonDeserializer(converter=MyConverter.class)
public class CustomDate {
    ...
}

which is slightly simpler with less code and no need for explicit registration. But it also adds direct dependency to jackson annotation from class, which some developers dislike.

-+ Tatu +-


--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Steve Bread

unread,
Sep 12, 2014, 12:38:39 PM9/12/14
to jackso...@googlegroups.com
Thanks Tatu. Unfortunately I cannot use JsonCreator because the ValueInstantiator actually doesn't create the instance directly but uses a service; I was trying to simplify it for the example. The method is actually

   public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) throws IOException, JsonProcessingException {
      return testService.create((CustomDate) args[0]);
   }

Thanks very much for confirming the code usage. I wasn't aware that I could define the converter with @JsonDeserialize. That's very convenient and I'll see if I can use it here or in the future.

Thanks!
Steve
Reply all
Reply to author
Forward
0 new messages