package com.fasterxml.jackson.databind.ser;
import java.util.*;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* Unit tests for verifying that field-backed properties can also be serialized
* (since version 1.1) as well as getter-accessible properties.
*/
public class FieldSerializationTest
extends BaseMapTest
{
/*
/**********************************************************
/* Annotated helper classes
/**********************************************************
*/
static class SimpleFieldBean
{
public int x, y;
// not auto-detectable, not public
int z;
// ignored, not detectable either
@JsonIgnore public int a;
}
static class SimpleFieldBean2
{
@JsonSerialize String[] values;
// note: this annotation should not matter for serialization:
@JsonDeserialize int dummy;
}
static class TransientBean
{
public int a;
// transients should not be included
public transient int b;
// or statics
public static int c;
}
@JsonAutoDetect(setterVisibility=Visibility.PUBLIC_ONLY, fieldVisibility=Visibility.NONE)
public class NoAutoDetectBean
{
// not auto-detectable any more
public int x;
@JsonProperty("z")
public int _z;
}
/**
* Let's test invalid bean too: can't have 2 logical properties
* with same name.
*<p>
* 21-Feb-2010, tatus: That is, not within same class.
* As per [JACKSON-226] it is acceptable to "override"
* field definitions in sub-classes.
*/
public static class DupFieldBean
{
@JsonProperty("foo")
public int _z;
@JsonSerialize
private int foo;
}
public static class DupFieldBean2
{
public int z;
@JsonProperty("z")
public int _z;
}
@SuppressWarnings("hiding")
public static class OkDupFieldBean
extends SimpleFieldBean
{
@JsonProperty("x")
protected int myX;
public int y;
public OkDupFieldBean(int x, int y) {
this.myX = x;
this.y = y;
}
}
/**
* It is ok to have a method-based and field-based property
* introspectable: only one should be serialized, and since
* methods have precedence, it should be the method one.
*/
public static class FieldAndMethodBean
{
@JsonProperty public int z;
@JsonProperty("z") public int getZ() { return z+1; }
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Item240 {
@JsonProperty
private String id;
// only include annotation to ensure it won't override settings
@JsonSerialize(typing=JsonSerialize.Typing.STATIC)
private String state;
public Item240(String id, String state) {
this.id = id;
this.state = state;
}
}
/*
/**********************************************************
/* Main tests, success
/**********************************************************
*/
private final ObjectMapper MAPPER = new ObjectMapper();
public void testSimpleAutoDetect() throws Exception
{
SimpleFieldBean bean = new SimpleFieldBean();
// let's set x, leave y as is
bean.x = 13;
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(2, result.size());
assertEquals(Integer.valueOf(13), result.get("x"));
assertEquals(Integer.valueOf(0), result.get("y"));
}
@SuppressWarnings("unchecked")
public void testSimpleAnnotation() throws Exception
{
SimpleFieldBean2 bean = new SimpleFieldBean2();
bean.values = new String[] { "a", "b" };
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
List<String> values = (List<String>) result.get("values");
assertEquals(2, values.size());
assertEquals("a", values.get(0));
assertEquals("b", values.get(1));
}
public void testTransientAndStatic() throws Exception
{
TransientBean bean = new TransientBean();
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
assertEquals(Integer.valueOf(0), result.get("a"));
}
public void testNoAutoDetect() throws Exception
{
NoAutoDetectBean bean = new NoAutoDetectBean();
bean._z = -4;
Map<String,Object> result = writeAndMap(MAPPER, bean);
assertEquals(1, result.size());
assertEquals(Integer.valueOf(-4), result.get("z"));
}
/**
* Unit test that verifies that if both a field and a getter
* method exist for a logical property (which is allowed),
* getter has precendence over field.
*/
public void testMethodPrecedence() throws Exception
{
FieldAndMethodBean bean = new FieldAndMethodBean();
bean.z = 9;
assertEquals(10, bean.getZ());
assertEquals("{\"z\":10}", MAPPER.writeValueAsString(bean));
}
/**
* Testing [JACKSON-226]: it is ok to have "field override",
* as long as there are no intra-class conflicts.
*/
public void testOkDupFields() throws Exception
{
OkDupFieldBean bean = new OkDupFieldBean(1, 2);
Map<String,Object> json = writeAndMap(MAPPER, bean);
assertEquals(2, json.size());
assertEquals(Integer.valueOf(1), json.get("x"));
assertEquals(Integer.valueOf(2), json.get("y"));
}
public void testIssue240() throws Exception
{
Item240 bean = new Item240("a12", null);
assertEquals(MAPPER.writeValueAsString(bean), "{\"id\":\"a12\"}");
}
/*
/**********************************************************
/* Main tests, failure cases
/**********************************************************
*/
public void testFailureDueToDups() throws Exception
{
try {
writeAndMap(MAPPER, new DupFieldBean());
} catch (JsonMappingException e) {
verifyException(e, "Multiple fields representing");
}
}
public void testFailureDueToDupField() throws Exception
{
try {
writeAndMap(MAPPER, new DupFieldBean2());
} catch (JsonMappingException e) {
verifyException(e, "Multiple fields representing");
}
}
}