问题
This is Jackson 2.2.x.
I have a class implementing JsonSerializable; there are two methods to implement for this interface, serialize()
and serializeWithType()
.
I want to test {de,}serialization of this class, and I can trigger calls to serialize()
easily; not, however, serializeWithType()
.
The javadoc for this latter method says that this method is called
[...] when additional type information is expected to be included in serialization, for deserialization to use.
I just don't understand what this means...
How do I set up a test environment so that this method be called? Note that the JSON to be serialized can be of any type except object (ie, boolean, number, string, array are all valid types).
回答1:
This method is used when you want to use polymorphism
public class A {
...
}
public class B extends A {
...
}
public class C extends A {
...
}
If you serialize an instance of C and then try to deserialize the resulting json but only knowing that its a sub-type of A :
final ObjectMapper objectMapper = new ObjectMapper();
final String json = objectMapper.writeValueAsString(new C());
final A deserialized = objectMapper.readValue(json, A.class);
You need something to be stored within the resulting JSON to keep the real type of the serialized object.
This can be enabled either using @JsonTypeInfo
on your class, or by calling enableDefaultTyping
on your ObjectMapper
.
This is a sample test case using JUnit & Mockito
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class SerializeWithTypeTest {
private JsonSerializable serializable = mock(JsonSerializable.class);
@Test
public void shouldCallSerializeWithType() throws Exception {
final ObjectMapper objectMapper = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.writeValueAsString(serializable);
// make sure serializeWithType is called once
verify(serializable, times(1)).serializeWithType(any(), any(), any());
}
}
回答2:
Jackson 2 is completely incompatible with Jackson 1, and JsonSerializableWithType
(Now deprecated and unusable) is an interface from Jackson 1 which led to the presence of serializeWithType()
in Jackson 2.
serializeWithType()
is called when additional type information is expected to be included, which means that an annotation (JsonTypeInfo
) is specifying the class property
for deserialization delegation, when polymorphism is used. This method will then be called with the additional type information within a TypeSerializer
, which may be written with a type prefix:
/* (.., .., TypeSerializer typeSer) */ {
typeSer.writeTypePrefixForScalar(.., .., ThisClass.class);
}
By annotating the class with @JsonTypeInfo
, you will be able to specify serializing with the type information:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = As.WRAPPER_OBJECT,
property = "type")
@JsonSubTypes({
@Type(name = "typeint", value = MyInt.class),
@Type(name = "typefloat", value = MyFloat.class)
})
public interface MyNumber {}
@JsonTypeName("typeint")
public MyInt implements MyNumber {}
@JsonTypeName("typefloat")
public MyFloat implements MyNumber {}
Then the values typeint
and typefloat
will be set in the property named type
. When you deserialize a MyNumber
, it will be based on polymorphism. Thomas Maurel's answer demonstrates a straightforward approach to test by serializing the object as string and deseralizing it.
回答3:
Try to use JsonTypeInfo annotation on your class. It should trigger calling serializeWithType()
. It is used to store info about type which is required for polymorphic types or to link abstract type and matching concrete implementation.
来源:https://stackoverflow.com/questions/26672297/how-to-trigger-calls-to-serializewithtype-of-a-class-implementing-jsonseriali