UnwrappedBasicTest.java
package tools.jackson.databind.struct;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import tools.jackson.databind.*;
import tools.jackson.databind.exc.UnrecognizedPropertyException;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for verifying that basic {@link JsonUnwrapped} annotation
* handling works as expected; some more advanced tests are separated out
* to more specific test classes (like prefix/suffix handling).
*/
public class UnwrappedBasicTest extends DatabindTestUtil
{
// // // Inner types for basic @JsonUnwrapped tests
static class Unwrapping {
public String name;
@JsonUnwrapped
public Location location;
public Unwrapping() { }
protected Unwrapping(String str, int x, int y) {
name = str;
location = new Location(x, y);
}
}
static class Location {
public int x;
public int y;
public Location() { }
public Location(int x, int y) {
this.x = x;
this.y = y;
}
}
static class DeepUnwrapping
{
@JsonUnwrapped
public Unwrapping unwrapped;
public DeepUnwrapping() { }
protected DeepUnwrapping(String str, int x, int y) {
unwrapped = new Unwrapping(str, x, y);
}
}
static class UnwrappingWithCreator {
public String name;
@JsonUnwrapped
public Location location;
@JsonCreator
public UnwrappingWithCreator(@JsonProperty("name") String n) {
name = n;
}
}
// Class with two unwrapped properties
static class TwoUnwrappedProperties {
@JsonUnwrapped
public Location location;
@JsonUnwrapped
public Name name;
public TwoUnwrappedProperties() { }
}
static class Name {
public String first, last;
}
// [databind#615]
static class Parent {
@JsonUnwrapped
public Child c1;
public Parent() { }
public Parent(String str) { c1 = new Child(str); }
}
static class Child {
public String field;
public Child() { }
public Child(String f) { field = f; }
}
static class Inner {
public String animal;
}
static class Outer {
@JsonUnwrapped
Inner inner;
}
// [databind#1493]: case-insensitive handling
static class Person {
@JsonUnwrapped(prefix = "businessAddress.")
public Address businessAddress;
}
static class Address {
public String street;
public String addon;
public String zip;
public String town;
public String country;
}
// [databind#383]
static class RecursivePerson {
public String name;
public int age;
@JsonUnwrapped(prefix="child.") public RecursivePerson child;
}
// [databind#647]
static class UnwrappedWithSamePropertyName {
public MailHolder mail;
}
static class MailHolder {
@JsonUnwrapped
public Mail mail;
}
static class Mail {
public String mail;
}
// [databind#81]
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="@type")
@JsonTypeName("OuterType")
static class Outer81 {
private @JsonProperty String p1;
public String getP1() { return p1; }
public void setP1(String p1) { this.p1 = p1; }
private Inner81 inner;
public void setInner(Inner81 inner) { this.inner = inner; }
@JsonUnwrapped
public Inner81 getInner() {
return inner;
}
}
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="@type")
@JsonTypeName("InnerType")
static class Inner81 {
private @JsonProperty String p2;
public String getP2() { return p2; }
public void setP2(String p2) { this.p2 = p2; }
}
// [databind#1559]
@JsonInclude(JsonInclude.Include.NON_EMPTY)
static final class Health {
@JsonUnwrapped(prefix="xxx.")
public Status status;
}
// NOTE: `final` is required to trigger [databind#1559]
static final class Status {
public String code;
}
// [databind#2461]
static class Base {
public String id;
Base(String id) {
this.id = id;
}
}
static class InnerContainer {
@JsonUnwrapped(prefix = "base.")
public Base base;
InnerContainer(Base base) {
this.base = base;
}
}
static class OuterContainer {
@JsonUnwrapped(prefix = "container.")
public InnerContainer container;
OuterContainer(InnerContainer container) {
this.container = container;
}
}
// [databind#3277]
static class Holder {
Object value1;
@JsonUnwrapped
Holder2 holder2;
public Object getValue1() {
return value1;
}
public void setValue1(Object value1) {
this.value1 = value1;
}
}
static class Holder2 {
Map<String, Object> data = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getData() {
return data;
}
@JsonAnySetter
public void setAny(String key, Object value) {
data.put(key, value);
}
}
// [databind#2088]
static class Issue2088Bean {
int x;
int y;
@JsonUnwrapped
Issue2088UnwrappedBean w;
public Issue2088Bean(@JsonProperty("x") int x, @JsonProperty("y") int y) {
this.x = x;
this.y = y;
}
public void setW(Issue2088UnwrappedBean w) {
this.w = w;
}
}
static class Issue2088UnwrappedBean {
int a;
int b;
public Issue2088UnwrappedBean(@JsonProperty("a") int a, @JsonProperty("b") int b) {
this.a = a;
this.b = b;
}
}
// // // Inner types for USE_NULL_FOR_EMPTY_UNWRAPPED tests [databind#1709]
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
static class Container1709 {
public String name;
@JsonUnwrapped
public Unwrapped1709 u;
}
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
static class Unwrapped1709 {
public String s;
public Integer n;
}
// // // Inner types for @JsonUnwrapped with @JsonCreator [databind#1467]
static class ExplicitWithoutName {
private final String _unrelated;
private final Inner1467 _inner;
@JsonCreator
public ExplicitWithoutName(@JsonProperty("unrelated") String unrelated, @JsonUnwrapped Inner1467 inner) {
_unrelated = unrelated;
_inner = inner;
}
public String getUnrelated() {
return _unrelated;
}
@JsonUnwrapped
public Inner1467 getInner() {
return _inner;
}
}
static class ExplicitWithName {
private final String _unrelated;
private final Inner1467 _inner;
@JsonCreator
public ExplicitWithName(@JsonProperty("unrelated") String unrelated, @JsonProperty("inner") @JsonUnwrapped Inner1467 inner) {
_unrelated = unrelated;
_inner = inner;
}
public String getUnrelated() {
return _unrelated;
}
public Inner1467 getInner() {
return _inner;
}
}
static class ImplicitWithName {
private final String _unrelated;
private final Inner1467 _inner;
public ImplicitWithName(@JsonProperty("unrelated") String unrelated, @JsonProperty("inner") @JsonUnwrapped Inner1467 inner) {
_unrelated = unrelated;
_inner = inner;
}
public String getUnrelated() {
return _unrelated;
}
public Inner1467 getInner() {
return _inner;
}
}
static class WithTwoUnwrappedProperties {
private final String _unrelated;
private final Inner1467 _inner1;
private final Inner1467 _inner2;
public WithTwoUnwrappedProperties(
@JsonProperty("unrelated") String unrelated,
@JsonUnwrapped(prefix = "first-") Inner1467 inner1,
@JsonUnwrapped(prefix = "second-") Inner1467 inner2
) {
_unrelated = unrelated;
_inner1 = inner1;
_inner2 = inner2;
}
public String getUnrelated() {
return _unrelated;
}
@JsonUnwrapped(prefix = "first-")
public Inner1467 getInner1() {
return _inner1;
}
@JsonUnwrapped(prefix = "second-")
public Inner1467 getInner2() {
return _inner2;
}
}
static class Inner1467 {
private final String _property1;
private final String _property2;
public Inner1467(@JsonProperty("property1") String property1, @JsonProperty("property2") String property2) {
_property1 = property1;
_property2 = property2;
}
public String getProperty1() {
return _property1;
}
public String getProperty2() {
return _property2;
}
}
static class PrefixOuter {
@JsonUnwrapped(prefix = "inner-")
PrefixInner inner;
}
static class PrefixInner {
private final String _property;
public PrefixInner(@JsonProperty("property") String property) {
_property = property;
}
public String getProperty() {
return _property;
}
}
// // // Inner types for @JsonUnwrapped with prefix/suffix tests
// Class with unwrapping using prefixes
static class PrefixUnwrap
{
public String name;
@JsonUnwrapped(prefix="_")
public Location location;
public PrefixUnwrap() { }
protected PrefixUnwrap(String str, int x, int y) {
name = str;
location = new Location(x, y);
}
}
static class DeepPrefixUnwrap
{
@JsonUnwrapped(prefix="u.")
public PrefixUnwrap unwrapped;
public DeepPrefixUnwrap() { }
protected DeepPrefixUnwrap(String str, int x, int y) {
unwrapped = new PrefixUnwrap(str, x, y);
}
}
// Let's actually test hierarchic names with unwrapping bit more:
@JsonPropertyOrder({ "general", "misc" })
static class ConfigRoot
{
@JsonUnwrapped(prefix="general.")
public ConfigGeneral general = new ConfigGeneral();
@JsonUnwrapped(prefix="misc.")
public ConfigMisc misc = new ConfigMisc();
public ConfigRoot() { }
protected ConfigRoot(String name, int value)
{
general = new ConfigGeneral(name);
misc.value = value;
}
}
static class ConfigAlternate
{
@JsonUnwrapped
public ConfigGeneral general = new ConfigGeneral();
@JsonUnwrapped(prefix="misc.")
public ConfigMisc misc = new ConfigMisc();
public int id;
public ConfigAlternate() { }
protected ConfigAlternate(int id, String name, int value)
{
this.id = id;
general = new ConfigGeneral(name);
misc.value = value;
}
}
static class ConfigGeneral
{
@JsonUnwrapped(prefix="names.")
public ConfigNames names = new ConfigNames();
public ConfigGeneral() { }
protected ConfigGeneral(String name) {
names.name = name;
}
}
static class ConfigNames {
public String name = "x";
}
static class ConfigMisc {
public int value;
}
// For [Issue#226]
static class Parent226 {
@JsonUnwrapped(prefix="c1.")
public Child226 c1;
@JsonUnwrapped(prefix="c2.")
public Child226 c2;
}
static class Child226 {
@JsonUnwrapped(prefix="sc2.")
public SubChild sc1;
}
static class SubChild {
public String value;
}
// // // Inner types for @JsonUnwrapped with unknown property handling [databind#650]
static class A650 {
@JsonUnwrapped
public B650 b;
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class A650WithUnknownsOk {
@JsonUnwrapped
public B650 b;
}
static class B650 {
public String field;
}
// For prefix/suffix
static class A650WithPrefix {
@JsonUnwrapped(prefix = "nested.")
public B650 b;
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class A650WithPrefixUnknownsOk {
@JsonUnwrapped(prefix = "nested.")
public B650 b;
}
// For @JsonCreator + @JsonUnwrapped
static class A650WithCreator {
public String name;
@JsonUnwrapped
public B650 b;
@JsonCreator
public A650WithCreator(@JsonProperty("name") String name) {
this.name = name;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class A650WithCreatorUnknownsOk {
public String name;
@JsonUnwrapped
public B650 b;
@JsonCreator
public A650WithCreatorUnknownsOk(@JsonProperty("name") String name) {
this.name = name;
}
}
// For @JsonCreator + @JsonUnwrapped with prefix
static class A650WithCreatorAndPrefix {
public String name;
@JsonUnwrapped(prefix = "nested.")
public B650 b;
@JsonCreator
public A650WithCreatorAndPrefix(@JsonProperty("name") String name) {
this.name = name;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class A650WithCreatorAndPrefixUnknownsOk {
public String name;
@JsonUnwrapped(prefix = "nested.")
public B650 b;
@JsonCreator
public A650WithCreatorAndPrefixUnknownsOk(@JsonProperty("name") String name) {
this.name = name;
}
}
/*
/**********************************************************
/* Mapper instances
/**********************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
// [databind#1709]
private final ObjectMapper MAPPER_ENABLED = jsonMapperBuilder()
.enable(DeserializationFeature.USE_NULL_FOR_EMPTY_UNWRAPPED)
.build();
private final ObjectMapper MAPPER_DISABLED = jsonMapperBuilder()
.disable(DeserializationFeature.USE_NULL_FOR_EMPTY_UNWRAPPED)
.build();
// [databind#650]: with FAIL_ON_UNKNOWN_PROPERTIES enabled
private final ObjectMapper STRICT_MAPPER = JsonMapper.builder()
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
/*
/**********************************************************
/* Tests, serialization
/**********************************************************
*/
@Test
public void testSimpleUnwrappingSerialize() throws Exception {
JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
assertEquals("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
mapper.writeValueAsString(new Unwrapping("Tatu", 1, 2)));
}
@Test
public void testDeepUnwrappingSerialize() throws Exception {
JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
assertEquals("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
mapper.writeValueAsString(new DeepUnwrapping("Tatu", 1, 2)));
}
/*
/**********************************************************
/* Tests, deserialization
/**********************************************************
*/
@Test
public void testSimpleUnwrappedDeserialize() throws Exception
{
Unwrapping bean = MAPPER.readValue("{\"name\":\"Tatu\",\"y\":7,\"x\":-13}",
Unwrapping.class);
assertEquals("Tatu", bean.name);
Location loc = bean.location;
assertNotNull(loc);
assertEquals(-13, loc.x);
assertEquals(7, loc.y);
}
@Test
public void testDoubleUnwrapping() throws Exception
{
TwoUnwrappedProperties bean = MAPPER.readValue("{\"first\":\"Joe\",\"y\":7,\"last\":\"Smith\",\"x\":-13}",
TwoUnwrappedProperties.class);
Location loc = bean.location;
assertNotNull(loc);
assertEquals(-13, loc.x);
assertEquals(7, loc.y);
Name name = bean.name;
assertNotNull(name);
assertEquals("Joe", name.first);
assertEquals("Smith", name.last);
}
@Test
public void testDeepUnwrapping() throws Exception
{
DeepUnwrapping bean = MAPPER.readValue("{\"x\":3,\"name\":\"Bob\",\"y\":27}",
DeepUnwrapping.class);
Unwrapping uw = bean.unwrapped;
assertNotNull(uw);
assertEquals("Bob", uw.name);
Location loc = uw.location;
assertNotNull(loc);
assertEquals(3, loc.x);
assertEquals(27, loc.y);
}
@Test
public void testUnwrappedDeserializeWithCreator() throws Exception
{
UnwrappingWithCreator bean = MAPPER.readValue("{\"x\":1,\"y\":2,\"name\":\"Tatu\"}",
UnwrappingWithCreator.class);
assertEquals("Tatu", bean.name);
Location loc = bean.location;
assertNotNull(loc);
assertEquals(1, loc.x);
assertEquals(2, loc.y);
}
@Test
public void testIssue615() throws Exception
{
Parent input = new Parent("name");
String json = MAPPER.writeValueAsString(input);
Parent output = MAPPER.readValue(json, Parent.class);
assertEquals("name", output.c1.field);
}
@Test
public void testUnwrappedAsPropertyIndicator() throws Exception
{
Inner inner = new Inner();
inner.animal = "Zebra";
Outer outer = new Outer();
outer.inner = inner;
String actual = MAPPER.writeValueAsString(outer);
assertTrue(actual.contains("animal"));
assertTrue(actual.contains("Zebra"));
assertFalse(actual.contains("inner"));
}
// [databind#1493]: case-insensitive handling
@Test
public void testCaseInsensitiveUnwrap() throws Exception
{
ObjectMapper mapper = jsonMapperBuilder()
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
.build();
Person p = mapper.readValue("{ }", Person.class);
assertNotNull(p);
}
// [databind#2088]: accidental skipping of values
@Test
public void testIssue2088UnwrappedFieldsAfterLastCreatorProp() throws Exception
{
Issue2088Bean bean = MAPPER.readValue("{\"x\":1,\"a\":2,\"y\":3,\"b\":4}", Issue2088Bean.class);
assertEquals(1, bean.x);
assertEquals(2, bean.w.a);
assertEquals(3, bean.y);
assertEquals(4, bean.w.b);
}
// [databind#383]
@Test
public void testRecursiveUsage() throws Exception
{
final String JSON = "{ 'name': 'Bob', 'age': 45, 'gender': 0, 'child.name': 'Bob jr', 'child.age': 15 }";
RecursivePerson p = MAPPER.readValue(a2q(JSON), RecursivePerson.class);
assertNotNull(p);
assertEquals("Bob", p.name);
assertNotNull(p.child);
assertEquals("Bob jr", p.child.name);
}
// [databind#647]
@Test
public void testUnwrappedWithSamePropertyName() throws Exception {
final String JSON = "{'mail': {'mail': 'the mail text'}}";
UnwrappedWithSamePropertyName result = MAPPER.readValue(a2q(JSON), UnwrappedWithSamePropertyName.class);
assertNotNull(result.mail);
assertNotNull(result.mail.mail);
assertEquals("the mail text", result.mail.mail.mail);
}
// [databind#81]
@Test
public void testDefaultUnwrappedWithTypeInfo() throws Exception
{
Outer81 outer = new Outer81();
outer.setP1("101");
Inner81 inner = new Inner81();
inner.setP2("202");
outer.setInner(inner);
try {
MAPPER.writeValueAsString(outer);
fail("Expected exception to be thrown.");
} catch (DatabindException ex) {
verifyException(ex, "requires use of type information");
}
}
// [databind#81]
@Test
public void testUnwrappedWithTypeInfoAndFeatureDisabled() throws Exception
{
Outer81 outer = new Outer81();
outer.setP1("101");
Inner81 inner = new Inner81();
inner.setP2("202");
outer.setInner(inner);
ObjectMapper mapper = jsonMapperBuilder()
.disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS)
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
.build();
String json = mapper.writeValueAsString(outer);
assertEquals("{\"@type\":\"OuterType\",\"p2\":\"202\",\"p1\":\"101\"}", json);
}
// [databind#1559]
@Test
public void testCanSerializeSimpleWithDefaultView() throws Exception
{
String json = jsonMapperBuilder()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.build()
.writeValueAsString(new Health());
assertEquals(a2q("{}"), json);
// and just in case this, although won't matter wrt output
json = jsonMapperBuilder()
.enable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.build()
.writeValueAsString(new Health());
assertEquals(a2q("{}"), json);
}
// [databind#2461]
@Test
public void testUnwrappedCaching() throws Exception {
final InnerContainer inner = new InnerContainer(new Base("12345"));
final OuterContainer outer = new OuterContainer(inner);
final String EXP_INNER = "{\"base.id\":\"12345\"}";
final String EXP_OUTER = "{\"container.base.id\":\"12345\"}";
final ObjectMapper mapperOrder1 = newJsonMapper();
assertEquals(EXP_OUTER, mapperOrder1.writeValueAsString(outer));
assertEquals(EXP_INNER, mapperOrder1.writeValueAsString(inner));
assertEquals(EXP_OUTER, mapperOrder1.writeValueAsString(outer));
final ObjectMapper mapperOrder2 = newJsonMapper();
assertEquals(EXP_INNER, mapperOrder2.writeValueAsString(inner));
// Used to fail here
assertEquals(EXP_OUTER, mapperOrder2.writeValueAsString(outer));
}
// [databind#3277]
@Test
public void testIsInstanceOfDouble() throws Exception
{
Holder holder = MAPPER.readValue("{\"value1\": -60.0, \"value2\": -60.0}", Holder.class);
// Validate type
assertEquals(Double.class, holder.value1.getClass());
assertEquals(Double.class, holder.holder2.data.get("value2").getClass());
// Validate value
assertEquals(-60.0, holder.value1);
assertEquals(-60.0, holder.holder2.data.get("value2"));
}
/*
/**********************************************************
/* Tests, USE_NULL_FOR_EMPTY_UNWRAPPED [databind#1709]
/**********************************************************
*/
@Test
public void testEmptyUnwrappedAsNull() throws Exception {
String json = a2q("{'name':'test'}");
Container1709 result = MAPPER_ENABLED.readValue(json, Container1709.class);
assertNotNull(result);
assertEquals("test", result.name);
assertNull(result.u);
}
@Test
public void testEmptyJsonEmptyUnwrappedAsNull() throws Exception {
Container1709 result = MAPPER_ENABLED.readValue("{}", Container1709.class);
assertNotNull(result);
assertNull(result.name);
assertNull(result.u);
}
@Test
public void testNonNullUnwrappedPreserved() throws Exception {
String json = a2q("{'name':'test','s':'value'}");
Container1709 result = MAPPER_ENABLED.readValue(json, Container1709.class);
assertNotNull(result);
assertEquals("test", result.name);
assertNotNull(result.u);
assertEquals("value", result.u.s);
}
@Test
public void testPartialNonNullUnwrappedPreserved() throws Exception {
String json = a2q("{'s':'value'}");
Container1709 result = MAPPER_ENABLED.readValue(json, Container1709.class);
assertNotNull(result);
assertNotNull(result.u);
assertEquals("value", result.u.s);
assertNull(result.u.n);
}
@Test
public void testEmptyUnwrappedAsNullWhenDisabled() throws Exception {
String json = a2q("{'name':'test'}");
Container1709 result = MAPPER_DISABLED.readValue(json, Container1709.class);
assertNotNull(result);
assertEquals("test", result.name);
assertNotNull(result.u);
assertNull(result.u.s);
assertNull(result.u.n);
}
@Test
public void testEmptyJsonEmptyUnwrappedAsNullWhenDisabled() throws Exception {
Container1709 result = MAPPER_DISABLED.readValue("{}", Container1709.class);
assertNotNull(result);
assertNull(result.name);
assertNotNull(result.u);
assertNull(result.u.s);
assertNull(result.u.n);
}
@Test
public void testNonNullUnwrappedPreservedWhenDisabled() throws Exception {
String json = a2q("{'name':'test','s':'value'}");
Container1709 result = MAPPER_DISABLED.readValue(json, Container1709.class);
assertNotNull(result);
assertEquals("test", result.name);
assertNotNull(result.u);
assertEquals("value", result.u.s);
}
@Test
public void testPartialNonNullUnwrappedPreservedWhenDisabled() throws Exception {
String json = a2q("{'s':'value'}");
Container1709 result = MAPPER_DISABLED.readValue(json, Container1709.class);
assertNull(result.u.n);
}
/*
/**********************************************************
/* Tests, @JsonUnwrapped with @JsonCreator [databind#1467]
/**********************************************************
*/
@Test
public void testUnwrappedWithJsonCreatorWithExplicitWithoutName() throws Exception
{
String json = "{\"unrelated\": \"unrelatedValue\", \"property1\": \"value1\", \"property2\": \"value2\"}";
ExplicitWithoutName outer = MAPPER.readValue(json, ExplicitWithoutName.class);
assertEquals("unrelatedValue", outer.getUnrelated());
assertEquals("value1", outer.getInner().getProperty1());
assertEquals("value2", outer.getInner().getProperty2());
}
@Test
public void testUnwrappedWithJsonCreatorExplicitWithName() throws Exception
{
String json = "{\"unrelated\": \"unrelatedValue\", \"property1\": \"value1\", \"property2\": \"value2\"}";
ExplicitWithName outer = MAPPER.readValue(json, ExplicitWithName.class);
assertEquals("unrelatedValue", outer.getUnrelated());
assertEquals("value1", outer.getInner().getProperty1());
assertEquals("value2", outer.getInner().getProperty2());
}
@Test
public void testUnwrappedWithJsonCreatorImplicitWithName() throws Exception
{
String json = "{\"unrelated\": \"unrelatedValue\", \"property1\": \"value1\", \"property2\": \"value2\"}";
ImplicitWithName outer = MAPPER.readValue(json, ImplicitWithName.class);
assertEquals("unrelatedValue", outer.getUnrelated());
assertEquals("value1", outer.getInner().getProperty1());
assertEquals("value2", outer.getInner().getProperty2());
}
@Test
public void testUnwrappedWithTwoUnwrappedProperties() throws Exception
{
String json = "{\"unrelated\": \"unrelatedValue\", " +
"\"first-property1\": \"first-value1\", \"first-property2\": \"first-value2\", " +
"\"second-property1\": \"second-value1\", \"second-property2\": \"second-value2\"}";
WithTwoUnwrappedProperties outer = MAPPER.readValue(json, WithTwoUnwrappedProperties.class);
assertEquals("unrelatedValue", outer.getUnrelated());
assertEquals("first-value1", outer.getInner1().getProperty1());
assertEquals("first-value2", outer.getInner1().getProperty2());
assertEquals("second-value1", outer.getInner2().getProperty1());
assertEquals("second-value2", outer.getInner2().getProperty2());
}
@Test
public void testUnwrappedWithPrefixCreator() throws Exception
{
String json = "{\"inner-property\": \"value\"}";
PrefixOuter outer = MAPPER.readValue(json, PrefixOuter.class);
assertEquals("value", outer.inner.getProperty());
}
/*
/**********************************************************
/* Tests, @JsonUnwrapped with prefix/suffix
/**********************************************************
*/
@Test
public void testPrefixedUnwrappingSerialize() throws Exception
{
JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
assertEquals("{\"_x\":1,\"_y\":2,\"name\":\"Tatu\"}",
mapper.writeValueAsString(new PrefixUnwrap("Tatu", 1, 2)));
}
@Test
public void testDeepPrefixedUnwrappingSerialize() throws Exception
{
JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
String json = mapper.writeValueAsString(new DeepPrefixUnwrap("Bubba", 1, 1));
assertEquals("{\"u._x\":1,\"u._y\":1,\"u.name\":\"Bubba\"}", json);
}
@Test
public void testHierarchicConfigSerialize() throws Exception
{
String json = MAPPER.writeValueAsString(new ConfigRoot("Fred", 25));
assertEquals("{\"general.names.name\":\"Fred\",\"misc.value\":25}", json);
}
@Test
public void testPrefixedUnwrapDeserialize() throws Exception
{
PrefixUnwrap bean = MAPPER.readValue("{\"name\":\"Axel\",\"_x\":4,\"_y\":7}", PrefixUnwrap.class);
assertNotNull(bean);
assertEquals("Axel", bean.name);
assertNotNull(bean.location);
assertEquals(4, bean.location.x);
assertEquals(7, bean.location.y);
}
@Test
public void testDeepPrefixedUnwrapDeserialize() throws Exception
{
DeepPrefixUnwrap bean = MAPPER.readValue("{\"u.name\":\"Bubba\",\"u._x\":2,\"u._y\":3}",
DeepPrefixUnwrap.class);
assertNotNull(bean.unwrapped);
assertNotNull(bean.unwrapped.location);
assertEquals(2, bean.unwrapped.location.x);
assertEquals(3, bean.unwrapped.location.y);
assertEquals("Bubba", bean.unwrapped.name);
}
@Test
public void testHierarchicConfigDeserialize() throws Exception
{
ConfigRoot root = MAPPER.readValue("{\"general.names.name\":\"Bob\",\"misc.value\":3}",
ConfigRoot.class);
assertNotNull(root.general);
assertNotNull(root.general.names);
assertNotNull(root.misc);
assertEquals(3, root.misc.value);
assertEquals("Bob", root.general.names.name);
}
@Test
public void testHierarchicConfigRoundTrip() throws Exception
{
ConfigAlternate input = new ConfigAlternate(123, "Joe", 42);
String json = MAPPER.writeValueAsString(input);
ConfigAlternate root = MAPPER.readValue(json, ConfigAlternate.class);
assertEquals(123, root.id);
assertNotNull(root.general);
assertNotNull(root.general.names);
assertNotNull(root.misc);
assertEquals("Joe", root.general.names.name);
assertEquals(42, root.misc.value);
}
// [Issue#226]
@Test
public void testIssue226() throws Exception
{
Parent226 input = new Parent226();
input.c1 = new Child226();
input.c1.sc1 = new SubChild();
input.c1.sc1.value = "a";
input.c2 = new Child226();
input.c2.sc1 = new SubChild();
input.c2.sc1.value = "b";
String json = MAPPER.writeValueAsString(input);
Parent226 output = MAPPER.readValue(json, Parent226.class);
assertNotNull(output.c1);
assertNotNull(output.c2);
assertNotNull(output.c1.sc1);
assertNotNull(output.c2.sc1);
assertEquals("a", output.c1.sc1.value);
assertEquals("b", output.c2.sc1.value);
}
/*
/**********************************************************
/* Tests, @JsonUnwrapped with unknown property handling [databind#650]
/**********************************************************
*/
@Test
public void testFailOnUnknownPropertyUnwrapped() throws Exception {
final String json = a2q("{'field': 'value', 'bad': 'bad value'}");
try {
STRICT_MAPPER.readValue(json, A650.class);
fail("Exception was not thrown on unknown property");
} catch (UnrecognizedPropertyException e) {
verifyException(e, "Unrecognized property");
}
}
@Test
public void testWorkOnUnknownWithAnnotation() throws Exception {
final String json = a2q("{'field': 'value', 'bad': 'bad value'}");
A650WithUnknownsOk a = STRICT_MAPPER.readValue(json, A650WithUnknownsOk.class);
assertEquals("value", a.b.field);
}
// Passing case, regular usage
@Test
public void testWorksOnRegularPropertyUnwrapped() throws Exception {
A650 value = STRICT_MAPPER.readValue(a2q("{'field': 'value'}"), A650.class);
assertEquals("value", value.b.field);
}
// Tests for @JsonUnwrapped with prefix
@Test
public void testFailOnUnknownPropertyUnwrappedWithPrefix() throws Exception {
final String json = a2q("{'nested.field': 'value', 'bad': 'bad value'}");
try {
STRICT_MAPPER.readValue(json, A650WithPrefix.class);
fail("Exception was not thrown on unknown property");
} catch (UnrecognizedPropertyException e) {
verifyException(e, "Unrecognized property");
}
}
@Test
public void testWorkOnUnknownWithPrefixAndAnnotation() throws Exception {
final String json = a2q("{'nested.field': 'value', 'bad': 'bad value'}");
A650WithPrefixUnknownsOk a = STRICT_MAPPER.readValue(json, A650WithPrefixUnknownsOk.class);
assertEquals("value", a.b.field);
}
@Test
public void testWorksOnRegularPropertyUnwrappedWithPrefix() throws Exception {
A650WithPrefix value = STRICT_MAPPER.readValue(a2q("{'nested.field': 'value'}"), A650WithPrefix.class);
assertEquals("value", value.b.field);
}
// Tests for @JsonCreator + @JsonUnwrapped (deserializeUsingPropertyBasedWithUnwrapped)
@Test
public void testFailOnUnknownPropertyWithCreator() throws Exception {
final String json = a2q("{'name': 'test', 'field': 'value', 'bad': 'bad value'}");
try {
STRICT_MAPPER.readValue(json, A650WithCreator.class);
fail("Exception was not thrown on unknown property");
} catch (UnrecognizedPropertyException e) {
verifyException(e, "Unrecognized property");
}
}
@Test
public void testWorkOnUnknownWithCreatorAndAnnotation() throws Exception {
final String json = a2q("{'name': 'test', 'field': 'value', 'bad': 'bad value'}");
A650WithCreatorUnknownsOk a = STRICT_MAPPER.readValue(json, A650WithCreatorUnknownsOk.class);
assertEquals("test", a.name);
assertEquals("value", a.b.field);
}
@Test
public void testWorksOnRegularPropertyWithCreator() throws Exception {
A650WithCreator value = STRICT_MAPPER.readValue(a2q("{'name': 'test', 'field': 'value'}"), A650WithCreator.class);
assertEquals("test", value.name);
assertEquals("value", value.b.field);
}
// Tests for @JsonCreator + @JsonUnwrapped with prefix
@Test
public void testFailOnUnknownPropertyWithCreatorAndPrefix() throws Exception {
final String json = a2q("{'name': 'test', 'nested.field': 'value', 'bad': 'bad value'}");
try {
STRICT_MAPPER.readValue(json, A650WithCreatorAndPrefix.class);
fail("Exception was not thrown on unknown property");
} catch (UnrecognizedPropertyException e) {
verifyException(e, "Unrecognized property");
}
}
@Test
public void testWorkOnUnknownWithCreatorAndPrefixAndAnnotation() throws Exception {
final String json = a2q("{'name': 'test', 'nested.field': 'value', 'bad': 'bad value'}");
A650WithCreatorAndPrefixUnknownsOk a = STRICT_MAPPER.readValue(json, A650WithCreatorAndPrefixUnknownsOk.class);
assertEquals("test", a.name);
assertEquals("value", a.b.field);
}
@Test
public void testWorksOnRegularPropertyWithCreatorAndPrefix() throws Exception {
A650WithCreatorAndPrefix value = STRICT_MAPPER.readValue(
a2q("{'name': 'test', 'nested.field': 'value'}"), A650WithCreatorAndPrefix.class);
assertEquals("test", value.name);
assertEquals("value", value.b.field);
}
}