package com.fasterxml.jackson.databind.struct; import java.io.IOException; import java.util.Map; import java.util.TreeMap; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; // Unit test for [JACKSON-890] public class TestBackRefsWithPolymorphic extends BaseMapTest { @JsonPropertyOrder(alphabetic=true) interface Entity { @JsonIgnore String getEntityType(); Long getId(); void setId(Long id); @JsonIgnore void setPersistable(); } @JsonDeserialize(as = NestedPropertySheetImpl.class) interface NestedPropertySheet extends Property<PropertySheet> { @Override PropertySheet getValue(); void setValue(PropertySheet propertySheet); } @JsonDeserialize(as = AbstractProperty.class) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") interface Property<T> extends Entity { String getName(); PropertySheet getParentSheet(); T getValue(); void setName(String name); void setParentSheet(PropertySheet parentSheet); } @JsonDeserialize(as = PropertySheetImpl.class) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") @SuppressWarnings("rawtypes") interface PropertySheet extends Entity { void addProperty(Property property); Map<String, Property> getProperties(); void setProperties(Map<String, Property> properties); } @JsonDeserialize(as = StringPropertyImpl.class) interface StringProperty extends Property<String> { @Override String getValue(); void setValue(String value); } static class AbstractEntity implements Entity { private long id; @Override public String getEntityType() { return ""; } @Override public Long getId() { return id; } @Override public void setId(Long id) { this.id = id; } @Override public void setPersistable() { } } abstract static class AbstractProperty<T> extends AbstractEntity implements Property<T> { private String m_name; private PropertySheet m_parentSheet; protected AbstractProperty() { } protected AbstractProperty(String name) { m_name = name; } @Override public String getName() { return m_name; } @JsonBackReference("propertySheet-properties") @Override public PropertySheet getParentSheet() { return m_parentSheet; } @Override public void setName(String name) { m_name = name; } @Override public void setParentSheet(PropertySheet parentSheet) { m_parentSheet = parentSheet; } } @JsonPropertyOrder(alphabetic=true) static class NestedPropertySheetImpl extends AbstractProperty<PropertySheet> implements NestedPropertySheet { private PropertySheet m_propertySheet; protected NestedPropertySheetImpl(String name, PropertySheet propertySheet) { super(name); m_propertySheet = propertySheet; } NestedPropertySheetImpl() { } @Override public PropertySheet getValue() { return m_propertySheet; } @Override public void setValue(PropertySheet propertySheet) { m_propertySheet = propertySheet; } } @SuppressWarnings("rawtypes") static class PropertySheetImpl extends AbstractEntity implements PropertySheet { private Map<String, Property> m_properties; @Override public void addProperty(Property property) { if (m_properties == null) { m_properties = new TreeMap<String, Property>(); } property.setParentSheet(this); m_properties.put(property.getName(), property); } @JsonDeserialize(as = TreeMap.class, keyAs = String.class, contentAs = Property.class) @JsonManagedReference("propertySheet-properties") @Override public Map<String, Property> getProperties() { return m_properties; } @Override public void setProperties(Map<String, Property> properties) { m_properties = properties; } } static class StringPropertyImpl extends AbstractProperty<String> implements StringProperty { private String m_value; public StringPropertyImpl(String name, String value) { super(name); m_value = value; } StringPropertyImpl() { } @Override public String getValue() { return m_value; } @Override public void setValue(String value) { m_value = value; } } static class YetAnotherClass extends StringPropertyImpl { } /* /********************************************************** /* Test methods /********************************************************** */ private final String CLASS_NAME = getClass().getName(); // NOTE: order is arbitrary, test is fragile... has to work for now private final String JSON = "{\"@class\":\""+CLASS_NAME+"$PropertySheetImpl\",\"id\":0,\"properties\":{\"p1name\":{\"@class\":" +"\"" +CLASS_NAME+ "$StringPropertyImpl\",\"id\":0,\"name\":\"p1name\",\"value\":\"p1value\"}," +"\"p2name\":{\"@class\":\""+CLASS_NAME+"$StringPropertyImpl\",\"id\":0," +"\"name\":\"p2name\",\"value\":\"p2value\"}}}"; private final ObjectMapper MAPPER = new ObjectMapper(); public void testDeserialize() throws IOException { PropertySheet input = MAPPER.readValue(JSON, PropertySheet.class); assertEquals(JSON, MAPPER.writeValueAsString(input)); } public void testSerialize() throws IOException { PropertySheet sheet = new PropertySheetImpl(); sheet.addProperty(new StringPropertyImpl("p1name", "p1value")); sheet.addProperty(new StringPropertyImpl("p2name", "p2value")); String actual = MAPPER.writeValueAsString(sheet); assertEquals(JSON, actual); } }