blob: f7246eeffb6f332ec760ed8ff7b5f5648a1a4e49 [file] [log] [blame]
package org.codehaus.jackson.map.module;
import java.io.IOException;
import java.lang.reflect.Type;
import org.codehaus.jackson.*;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.type.CollectionLikeType;
import org.codehaus.jackson.map.type.MapLikeType;
import org.codehaus.jackson.map.type.TypeBindings;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.map.type.TypeModifier;
import org.codehaus.jackson.type.JavaType;
public class TestTypeModifiers extends BaseMapTest
{
/*
/**********************************************************
/* Helper classes
/**********************************************************
*/
static class ModifierModule extends SimpleModule
{
public ModifierModule() {
super("test", Version.unknownVersion());
}
@Override
public void setupModule(SetupContext context)
{
context.addSerializers(new Serializers.Base() {
@Override
public JsonSerializer<?> findMapLikeSerializer(SerializationConfig config,
MapLikeType type, BeanDescription beanDesc, BeanProperty property,
JsonSerializer<Object> keySerializer,
TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
{
if (MapMarker.class.isAssignableFrom(type.getRawClass())) {
return new MyMapSerializer(keySerializer, elementValueSerializer);
}
return null;
}
@Override
public JsonSerializer<?> findCollectionLikeSerializer(SerializationConfig config,
CollectionLikeType type, BeanDescription beanDesc, BeanProperty property,
TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
{
if (CollectionMarker.class.isAssignableFrom(type.getRawClass())) {
return new MyCollectionSerializer();
}
return null;
}
});
context.addDeserializers(new SimpleDeserializers() {
@Override
public JsonDeserializer<?> findCollectionLikeDeserializer(CollectionLikeType type, DeserializationConfig config,
DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
if (CollectionMarker.class.isAssignableFrom(type.getRawClass())) {
return new MyCollectionDeserializer();
}
return null;
}
@Override
public JsonDeserializer<?> findMapLikeDeserializer(MapLikeType type, DeserializationConfig config,
DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property,
KeyDeserializer keyDeserializer,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
if (MapMarker.class.isAssignableFrom(type.getRawClass())) {
return new MyMapDeserializer();
}
return null;
}
});
}
}
static class XxxSerializer extends JsonSerializer<Object>
{
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString("xxx:"+value);
}
}
interface MapMarker<K,V> {
public K getKey();
public V getValue();
}
interface CollectionMarker<V> {
public V getValue();
}
@JsonSerialize(contentUsing=XxxSerializer.class)
static class MyMapLikeType implements MapMarker<String,Integer> {
public String key;
public int value;
public MyMapLikeType() { }
public MyMapLikeType(String k, int v) {
key = k;
value = v;
}
@Override
public String getKey() { return key; }
@Override
public Integer getValue() { return value; }
}
static class MyCollectionLikeType implements CollectionMarker<Integer>
{
public int value;
public MyCollectionLikeType() { }
public MyCollectionLikeType(int v) {
value = v;
}
@Override
public Integer getValue() { return value; }
}
static class MyMapSerializer extends JsonSerializer<MapMarker<?,?>>
{
protected final JsonSerializer<Object> _keySerializer;
protected final JsonSerializer<Object> _valueSerializer;
public MyMapSerializer(JsonSerializer<Object> keySer, JsonSerializer<Object> valueSer) {
_keySerializer = keySer;
_valueSerializer = valueSer;
}
@Override
public void serialize(MapMarker<?,?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
if (_keySerializer == null) {
jgen.writeFieldName((String) value.getKey());
} else {
_keySerializer.serialize(value.getKey(), jgen, provider);
}
if (_valueSerializer == null) {
jgen.writeNumber(((Number) value.getValue()).intValue());
} else {
_valueSerializer.serialize(value.getValue(), jgen, provider);
}
jgen.writeEndObject();
}
}
static class MyMapDeserializer extends JsonDeserializer<MapMarker<?,?>>
{
@Override
public MapMarker<?,?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
if (jp.getCurrentToken() != JsonToken.START_OBJECT) throw new IOException("Wrong token: "+jp.getCurrentToken());
if (jp.nextToken() != JsonToken.FIELD_NAME) throw new IOException("Wrong token: "+jp.getCurrentToken());
String key = jp.getCurrentName();
if (jp.nextToken() != JsonToken.VALUE_NUMBER_INT) throw new IOException("Wrong token: "+jp.getCurrentToken());
int value = jp.getIntValue();
if (jp.nextToken() != JsonToken.END_OBJECT) throw new IOException("Wrong token: "+jp.getCurrentToken());
return new MyMapLikeType(key, value);
}
}
static class MyCollectionSerializer extends JsonSerializer<MyCollectionLikeType>
{
@Override
public void serialize(MyCollectionLikeType value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartArray();
jgen.writeNumber(value.value);
jgen.writeEndArray();
}
}
static class MyCollectionDeserializer extends JsonDeserializer<MyCollectionLikeType>
{
@Override
public MyCollectionLikeType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
if (jp.getCurrentToken() != JsonToken.START_ARRAY) throw new IOException("Wrong token: "+jp.getCurrentToken());
if (jp.nextToken() != JsonToken.VALUE_NUMBER_INT) throw new IOException("Wrong token: "+jp.getCurrentToken());
int value = jp.getIntValue();
if (jp.nextToken() != JsonToken.END_ARRAY) throw new IOException("Wrong token: "+jp.getCurrentToken());
return new MyCollectionLikeType(value);
}
}
static class MyTypeModifier extends TypeModifier
{
@Override
public JavaType modifyType(JavaType type, Type jdkType, TypeBindings context, TypeFactory typeFactory)
{
Class<?> raw = type.getRawClass();
if (MapMarker.class.isAssignableFrom(raw)) {
JavaType[] params = typeFactory.findTypeParameters(type, MapMarker.class);
return typeFactory.constructMapLikeType(raw, params[0], params[1]);
}
if (CollectionMarker.class.isAssignableFrom(raw)) {
JavaType[] params = typeFactory.findTypeParameters(type, CollectionMarker.class);
return typeFactory.constructCollectionLikeType(raw, params[0]);
}
return type;
}
}
/*
/**********************************************************
/* Unit tests
/**********************************************************
*/
/**
* Basic test for ensuring that we can get "xxx-like" types recognized.
*/
public void testLikeTypeConstruction() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setTypeFactory(mapper.getTypeFactory().withModifier(new MyTypeModifier()));
JavaType type = mapper.constructType(MyMapLikeType.class);
assertTrue(type.isMapLikeType());
// also, must have resolved type info
JavaType param = ((MapLikeType) type).getKeyType();
assertNotNull(param);
assertSame(String.class, param.getRawClass());
param = ((MapLikeType) type).getContentType();
assertNotNull(param);
assertSame(Integer.class, param.getRawClass());
type = mapper.constructType(MyCollectionLikeType.class);
assertTrue(type.isCollectionLikeType());
param = ((CollectionLikeType) type).getContentType();
assertNotNull(param);
assertSame(Integer.class, param.getRawClass());
}
public void testCollectionLikeSerialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setTypeFactory(mapper.getTypeFactory().withModifier(new MyTypeModifier()));
mapper.registerModule(new ModifierModule());
assertEquals("[19]", mapper.writeValueAsString(new MyCollectionLikeType(19)));
}
public void testMapLikeSerialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setTypeFactory(mapper.getTypeFactory().withModifier(new MyTypeModifier()));
mapper.registerModule(new ModifierModule());
// Due to custom serializer, should get:
assertEquals("{\"x\":\"xxx:3\"}", mapper.writeValueAsString(new MyMapLikeType("x", 3)));
}
public void testCollectionLikeDeserialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setTypeFactory(mapper.getTypeFactory().withModifier(new MyTypeModifier()));
mapper.registerModule(new ModifierModule());
// !!! TBI
MyMapLikeType result = mapper.readValue("{\"a\":13}", MyMapLikeType.class);
assertEquals("a", result.getKey());
assertEquals(Integer.valueOf(13), result.getValue());
}
public void testMapLikeDeserialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.setTypeFactory(mapper.getTypeFactory().withModifier(new MyTypeModifier()));
mapper.registerModule(new ModifierModule());
// !!! TBI
MyCollectionLikeType result = mapper.readValue("[-37]", MyCollectionLikeType.class);
assertEquals(Integer.valueOf(-37), result.getValue());
}
}