UntypedObjectWithDupsTest.java
package com.fasterxml.jackson.databind.interop;
import java.util.*;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.StreamReadCapability;
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import com.fasterxml.jackson.core.util.JsonParserDelegate;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.assertEquals;
// Mostly for XML but can be tested via JSON with some trickery
public class UntypedObjectWithDupsTest extends DatabindTestUtil
{
private final ObjectMapper JSON_MAPPER = newJsonMapper();
@SuppressWarnings("serial")
static class StringStringMap extends LinkedHashMap<String,String> { };
private final String DOC_WITH_DUPS = a2q(
"{'hello': 'world',\n"
+ "'lists' : 1,\n"
+ "'lists' : 2,\n"
+ "'lists' : {\n"
+ " 'inner' : 'internal',\n"
+ " 'time' : 123\n"
+ "},\n"
+ "'lists' : 3,\n"
+ "'single' : 'one'\n"
+ "}");
// Testing the baseline non-merging behavior
@Test
public void testDocWithDupsNoMerging() throws Exception
{
_verifyDupsNoMerging(Object.class);
_verifyDupsNoMerging(Map.class);
}
// For [dataformat-xml#???]
@Test
public void testDocWithDupsAsUntyped() throws Exception
{
_verifyDupsAreMerged(Object.class);
}
// For [dataformat-xml#498] / [databind#3484]
@Test
public void testDocWithDupsAsMap() throws Exception
{
_verifyDupsAreMerged(Map.class);
}
// And also verify that Maps with values other than `Object` will
// NOT try merging no matter what
@Test
public void testDocWithDupsAsNonUntypedMap() throws Exception
{
final String DOC = a2q("{'key':'a','key':'b'}");
assertEquals(a2q("{'key':'b'}"),
_readWriteDupDoc(DOC, StringStringMap.class));
}
/*
///////////////////////////////////////////////////////////////////////
// Helper methods
///////////////////////////////////////////////////////////////////////
*/
/* Method that will verify default JSON behavior of overwriting value
* (no merging).
*/
private <T> void _verifyDupsNoMerging(Class<T> cls) throws Exception
{
// This is where need some trickery
T value;
try (JsonParser p = JSON_MAPPER.createParser(DOC_WITH_DUPS)) {
value = JSON_MAPPER.readValue(p, cls);
}
String json = JSON_MAPPER.writeValueAsString(value);
assertEquals(a2q(
"{'hello':'world','lists':3,'single':'one'}"),
json);
}
/* Method that will verify alternate behavior (used by XML module f.ex)
* in which duplicate "properties" are merged into `List`s as necessary
*/
private void _verifyDupsAreMerged(Class<?> cls) throws Exception
{
assertEquals(a2q(
"{'hello':'world','lists':[1,2,"
+"{'inner':'internal','time':123},3],'single':'one'}"),
_readWriteDupDoc(DOC_WITH_DUPS, cls));
}
private String _readWriteDupDoc(String doc, Class<?> cls) throws Exception
{
// This is where need some trickery
Object value;
try (JsonParser p = new WithDupsParser(JSON_MAPPER.createParser(doc))) {
value = JSON_MAPPER.readValue(p, cls);
}
return JSON_MAPPER.writeValueAsString(value);
}
/**
* Helper class to fake "DUPLICATE_PROPERTIES" on JSON parser
* (which usually does not expose this).
*/
static class WithDupsParser extends JsonParserDelegate
{
public WithDupsParser(JsonParser p) {
super(p);
}
@Override
public JacksonFeatureSet<StreamReadCapability> getReadCapabilities() {
JacksonFeatureSet<StreamReadCapability> caps = super.getReadCapabilities();
caps = caps.with(StreamReadCapability.DUPLICATE_PROPERTIES);
return caps;
}
}
}