package com.fasterxml.jackson.databind.ser;
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* This unit test suite tests use of Annotations for
* bean serialization.
*/
public class TestAnnotations
extends BaseMapTest
{
/*
/**********************************************************
/* Helper classes
/**********************************************************
*/
/// Class for testing {@link JsonProperty} annotations with getters
final static class SizeClassGetter
{
@JsonProperty public int size() { return 3; }
@JsonProperty("length") public int foobar() { return -17; }
// note: need not be public since there's annotation
@JsonProperty protected int value() { return 0; }
// dummy method; not a getter signature
protected int getNotReally(int arg) { return 0; }
}
// And additional testing to cover [JACKSON-64]
final static class SizeClassGetter2
{
// Should still be considered property "x"
@JsonProperty protected int getX() { return 3; }
}
// and some support for testing [JACKSON-120]
final static class SizeClassGetter3
{
// Should be considered property "y" even tho non-public
@JsonSerialize protected int getY() { return 8; }
}
/**
* Class for testing {@link JsonSerializer} annotation
* for class itself.
*/
@JsonSerialize(using=BogusSerializer.class)
final static class ClassSerializer {
}
/**
* Class for testing an active {@link JsonSerialize#using} annotation
* for a method
*/
final static class ClassMethodSerializer {
private int _x;
public ClassMethodSerializer(int x) { _x = x; }
@JsonSerialize(using=StringSerializer.class)
public int getX() { return _x; }
}
/**
* Class for testing an inactive (one that will not have any effect)
* {@link JsonSerialize} annotation for a method
*/
final static class InactiveClassMethodSerializer {
private int _x;
public InactiveClassMethodSerializer(int x) { _x = x; }
// Basically, has no effect, hence gets serialized as number
@JsonSerialize(using=JsonSerializer.None.class)
public int getX() { return _x; }
}
/**
* Class for verifying that getter information is inherited
* as expected via normal class inheritance
*/
static class BaseBean {
public int getX() { return 1; }
@JsonProperty("y")
private int getY() { return 2; }
}
static class SubClassBean extends BaseBean {
public int getZ() { return 3; }
}
// For [JACKSON-666] ("SerializationFeature of the Beast!")
@JsonPropertyOrder(alphabetic=true)
static class GettersWithoutSetters
{
public int d = 0;
@JsonCreator
public GettersWithoutSetters(@JsonProperty("a") int a) { }
// included, since there is a constructor property
public int getA() { return 3; }
// not included, as there's nothing matching
public int getB() { return 4; }
// include as there is setter
public int getC() { return 5; }
public void setC(int v) { }
// and included, as there is a field
public int getD() { return 6; }
}
// [JACKSON-806]: override 'need-setter' with explicit annotation
static class GettersWithoutSetters2
{
@JsonProperty
public int getA() { return 123; }
}
/*
/**********************************************************
/* Other helper classes
/**********************************************************
*/
public final static class BogusSerializer extends JsonSerializer<Object>
{
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
jgen.writeBoolean(true);
}
}
private final static class StringSerializer extends JsonSerializer<Object>
{
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
jgen.writeString("X"+value+"X");
}
}
/*
/**********************************************************
/* Main tests
/**********************************************************
*/
private final ObjectMapper MAPPER = new ObjectMapper();
public void testSimpleGetter() throws Exception
{
Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter());
assertEquals(3, result.size());
assertEquals(Integer.valueOf(3), result.get("size"));
assertEquals(Integer.valueOf(-17), result.get("length"));
assertEquals(Integer.valueOf(0), result.get("value"));
}
public void testSimpleGetter2() throws Exception
{
Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter2());
assertEquals(1, result.size());
assertEquals(Integer.valueOf(3), result.get("x"));
}
// testing [JACKSON-120], implied getter
public void testSimpleGetter3() throws Exception
{
Map<String,Object> result = writeAndMap(MAPPER, new SizeClassGetter3());
assertEquals(1, result.size());
assertEquals(Integer.valueOf(8), result.get("y"));
}
/**
* Let's also verify that inherited super-class getters are used
* as expected
*/
public void testGetterInheritance() throws Exception
{
Map<String,Object> result = writeAndMap(MAPPER, new SubClassBean());
assertEquals(3, result.size());
assertEquals(Integer.valueOf(1), result.get("x"));
assertEquals(Integer.valueOf(2), result.get("y"));
assertEquals(Integer.valueOf(3), result.get("z"));
}
/**
* Unit test to verify that {@link JsonSerialize#using} annotation works
* when applied to a class
*/
public void testClassSerializer() throws Exception
{
StringWriter sw = new StringWriter();
MAPPER.writeValue(sw, new ClassSerializer());
assertEquals("true", sw.toString());
}
/**
* Unit test to verify that @JsonSerializer annotation works
* when applied to a Method
*/
public void testActiveMethodSerializer() throws Exception
{
StringWriter sw = new StringWriter();
MAPPER.writeValue(sw, new ClassMethodSerializer(13));
/* Here we will get wrapped as an object, since we have
* full object, just override a single property
*/
assertEquals("{\"x\":\"X13X\"}", sw.toString());
}
public void testInactiveMethodSerializer() throws Exception
{
String json = MAPPER.writeValueAsString(new InactiveClassMethodSerializer(8));
/* Here we will get wrapped as an object, since we have
* full object, just override a single property
*/
assertEquals("{\"x\":8}", json);
}
public void testGettersWithoutSetters() throws Exception
{
ObjectMapper m = new ObjectMapper();
GettersWithoutSetters bean = new GettersWithoutSetters(123);
assertFalse(m.isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS));
// by default, all 4 found:
assertEquals("{\"a\":3,\"b\":4,\"c\":5,\"d\":6}", m.writeValueAsString(bean));
// but 3 if we require mutator:
m = new ObjectMapper();
m.enable(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS);
assertEquals("{\"a\":3,\"c\":5,\"d\":6}", m.writeValueAsString(bean));
}
public void testGettersWithoutSettersOverride() throws Exception
{
GettersWithoutSetters2 bean = new GettersWithoutSetters2();
ObjectMapper m = new ObjectMapper();
m.enable(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS);
assertEquals("{\"a\":123}", m.writeValueAsString(bean));
}
}