#1839 - Fix JSON marshalling of @ElementCollection maps and scalar

This commit is contained in:
rob bygrave
2019-10-10 21:32:44 +13:00
parent 20dd33ebca
commit 8890079b80
17 changed files with 206 additions and 45 deletions
@@ -62,6 +62,16 @@ public interface SpiJsonWriter extends JsonWriter {
*/
void endAssocMany();
/**
* Start a Many.
*/
void beginAssocManyMap(String name, boolean elementCollection);
/**
* End a Many.
*/
void endAssocManyMap(boolean elementCollection);
/**
* Write value using underlying Jaskson object mapper if available.
*/
@@ -3549,6 +3549,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
throw new IllegalStateException("Unexpected - expect Element override");
}
public boolean isJsonReadCollection() {
return false;
}
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
jsonHelp.jsonWrite(writeJson, bean, null);
}
@@ -21,6 +21,11 @@ abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
this.elementHelp = elementHelp;
}
@Override
public boolean isJsonReadCollection() {
return true;
}
/**
* Find and return the first base scalar type (and we expect only 1).
*/
@@ -35,6 +35,11 @@ class BeanDescriptorElementEmbedded<T> extends BeanDescriptorElement<T> {
}
}
@Override
public boolean isJsonReadCollection() {
return false;
}
@Override
public void initialiseOther(BeanDescriptorInitContext initContext) {
super.initialiseOther(initContext);
@@ -28,10 +28,14 @@ class BeanDescriptorElementEmbeddedMap<T> extends BeanDescriptorElementEmbedded<
this.stringKey = String.class.equals(scalarTypeKey.getType());
}
@Override
public boolean isJsonReadCollection() {
return true;
}
@Override
@SuppressWarnings("unchecked")
public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry<?, ?> entry) throws IOException {
ctx.writeStartObject();
if (stringKey) {
Object key = entry.getKey();
String keyName = (key == null) ? "null" : key.toString();
@@ -43,7 +47,6 @@ class BeanDescriptorElementEmbeddedMap<T> extends BeanDescriptorElementEmbedded<
ctx.writeFieldName("value");
writeJsonElement(ctx, entry.getValue());
}
ctx.writeEndObject();
}
@Override
@@ -52,30 +55,21 @@ class BeanDescriptorElementEmbeddedMap<T> extends BeanDescriptorElementEmbedded<
JsonParser parser = readJson.getParser();
ElementCollector add = elementHelp.createCollector();
do {
JsonToken token = parser.nextToken();
if (token != JsonToken.START_OBJECT) {
String fieldName = parser.nextFieldName();
if (fieldName == null) {
break;
}
if (stringKey) {
String key = parser.nextFieldName();
parser.nextToken();
Object val = readJsonElement(readJson, null);
add.addKeyValue(key, val);
add.addKeyValue(fieldName, val);
} else {
parser.nextFieldName();
Object key = scalarTypeKey.jsonRead(parser);
parser.nextFieldName();
Object val = readJsonElement(readJson, null);
add.addKeyValue(key, val);
}
token = parser.nextToken();
if (token != JsonToken.END_OBJECT) {
break;
}
} while (true);
return add.collection();
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
@@ -35,7 +34,6 @@ class BeanDescriptorElementScalarMap<T> extends BeanDescriptorElement<T> {
@Override
@SuppressWarnings("unchecked")
public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry<?, ?> entry) throws IOException {
ctx.writeStartObject();
if (stringKey) {
Object key = entry.getKey();
String keyName = (key == null) ? "null" : key.toString();
@@ -47,7 +45,6 @@ class BeanDescriptorElementScalarMap<T> extends BeanDescriptorElement<T> {
ctx.writeFieldName("value");
scalarTypeVal.jsonWrite(ctx.gen(), entry.getValue());
}
ctx.writeEndObject();
}
@Override
@@ -56,30 +53,21 @@ class BeanDescriptorElementScalarMap<T> extends BeanDescriptorElement<T> {
JsonParser parser = readJson.getParser();
ElementCollector add = elementHelp.createCollector();
do {
JsonToken token = parser.nextToken();
if (token != JsonToken.START_OBJECT) {
String fieldName = parser.nextFieldName();
if (fieldName == null) {
break;
}
if (stringKey) {
String key = parser.nextFieldName();
parser.nextToken();
Object val = scalarTypeVal.jsonRead(parser);
add.addKeyValue(key, val);
add.addKeyValue(fieldName, val);
} else {
parser.nextFieldName();
Object key = scalarTypeKey.jsonRead(parser);
parser.nextFieldName();
Object val = scalarTypeVal.jsonRead(parser);
add.addKeyValue(key, val);
}
token = parser.nextToken();
if (token != JsonToken.END_OBJECT) {
break;
}
} while (true);
return add.collection();
@@ -163,11 +163,12 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
}
if (!map.isEmpty() || ctx.isIncludeEmpty()) {
ctx.beginAssocMany(name);
final boolean elementCollection = many.isElementCollection();
ctx.beginAssocManyMap(name, elementCollection);
for (Entry<?, ?> entry : map.entrySet()) {
many.jsonWriteMapEntry(ctx, entry);
}
ctx.endAssocMany();
ctx.endAssocManyMap(elementCollection);
}
}
@@ -971,7 +971,11 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry<?, ?> entry) throws IOException {
elementDescriptor.jsonWriteMapEntry(ctx, entry);
if (elementDescriptor != null) {
elementDescriptor.jsonWriteMapEntry(ctx, entry);
} else {
targetDescriptor.jsonWrite(ctx, (EntityBean)entry.getValue());
}
}
void jsonWriteElementValue(SpiJsonWriter ctx, Object element) {
@@ -1051,10 +1055,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
*/
public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException {
if (elementDescriptor != null && manyType.isMap()) {
if (elementDescriptor != null && elementDescriptor.isJsonReadCollection()) {
return elementDescriptor.jsonReadCollection(readJson, parentBean);
}
BeanCollection<?> collection = createEmpty(parentBean);
BeanCollectionAdd add = getBeanCollectionAdd(collection);
do {
@@ -40,22 +40,18 @@ class BeanPropertyAssocManyJsonHelp {
if (!this.many.jsonDeserialize) {
return;
}
JsonParser parser = readJson.getParser();
JsonToken event = parser.nextToken();
if (JsonToken.VALUE_NULL == event) {
return;
}
if (many.isTransient()) {
jsonReadTransientUsingObjectMapper(readJson, parentBean);
return;
}
if (JsonToken.START_ARRAY != event) {
throw new JsonParseException(parser, "Unexpected token " + event + " - expecting start_array");
if (JsonToken.START_ARRAY != event && JsonToken.START_OBJECT != event) {
throw new JsonParseException(parser, "Unexpected token " + event + " - expecting start array or object");
}
many.setValue(parentBean, many.jsonReadCollection(readJson, parentBean));
}
@@ -398,6 +398,37 @@ public class WriteJson implements SpiJsonWriter {
}
}
@Override
public void beginAssocManyMap(String key, boolean elementCollection) {
try {
pathStack.pushPathKey(key);
if (key != null) {
generator.writeFieldName(key);
}
if (elementCollection) {
generator.writeStartObject();
} else {
generator.writeStartArray();
}
} catch (IOException e) {
throw new JsonIOException(e);
}
}
@Override
public void endAssocManyMap(boolean elementCollection) {
try {
pathStack.pop();
if (elementCollection) {
generator.writeEndObject();
} else {
generator.writeEndArray();
}
} catch (IOException e) {
throw new JsonIOException(e);
}
}
@Override
public <T> void writeBean(BeanDescriptor<T> desc, EntityBean bean) {
createWriteBean(desc, bean).write(this);