Skip to content

Commit

Permalink
Refactored caching serializer in Map and Collection serializer, added…
Browse files Browse the repository at this point in the history
… caching into Array serializer.

Dependency on jsonp 1.1.2

Signed-off-by: Roman Grigoriadi <roman.grigoriadi@oracle.com>
  • Loading branch information
Roman Grigoriadi committed Nov 3, 2017
1 parent f26d92d commit a2a767f
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 73 deletions.
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
<name>Maven Java Net Snapshots and Releases</name>
<url>https://maven.java.net/content/groups/public/</url>
</repository>
<repository>
<id>java.net-Staging</id>
<name>Maven Java Net Staging</name>
<url>https://maven.java.net/content/groups/staging/</url>
</repository>
</repositories>

<groupId>org.eclipse</groupId>
Expand Down Expand Up @@ -115,7 +120,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javax.json.version>1.2-SNAPSHOT</javax.json.version>
<javax.json.version>1.1.2</javax.json.version>
<javax.json.bind.version>1.0</javax.json.bind.version>
<netbeans.hint.jdkPlatform>JDK_9</netbeans.hint.jdkPlatform>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@

package org.eclipse.yasson.internal.serializer;

import org.eclipse.yasson.internal.JsonbContext;
import org.eclipse.yasson.internal.Marshaller;
import org.eclipse.yasson.internal.ReflectionUtils;
import org.eclipse.yasson.internal.model.ClassModel;
import org.eclipse.yasson.internal.model.JsonBindingModel;

import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
import javax.json.stream.JsonGenerator;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.Optional;

/**
* Base class for container serializers (list, array, etc.).
Expand All @@ -28,6 +33,10 @@
*/
public abstract class AbstractContainerSerializer<T> extends AbstractItem<T> implements JsonbSerializer<T> {

private JsonbSerializer<?> valueSerializer;

private Class<?> valueClass;

/**
* Create instance of current item with its builder.
*
Expand Down Expand Up @@ -85,4 +94,42 @@ protected void writeEnd(JsonGenerator generator) {
protected <X> void serializerCaptor(JsonbSerializer<?> serializer, X object, JsonGenerator generator, SerializationContext ctx) {
((JsonbSerializer<X>) serializer).serialize(object, generator, ctx);
}

/**
* Return last used serializer if last value class matches.
* @param valueClass class of the serialized object
* @return cached serializer or null
*/
protected JsonbSerializer<?> getValueSerializer(Class<?> valueClass) {
if (valueSerializer != null && valueClass == this.valueClass) {
return valueSerializer;
}
return null;
}

/**
* Cache a serializer and serialized object class for next use.
* @param valueSerializer serializer
* @param valueClass class of serializer object
*/
protected void addValueSerializer(JsonbSerializer<?> valueSerializer, Class<?> valueClass) {
Objects.requireNonNull(valueSerializer);
Objects.requireNonNull(valueClass);
this.valueSerializer = valueSerializer;
this.valueClass = valueClass;
}

protected void serializeItem(Object item, JsonGenerator generator, SerializationContext ctx, JsonBindingModel model) {
if (item == null) {
generator.writeNull();
return;
}
Class<?> itemClass = item.getClass();
JsonbSerializer<?> serializer = getValueSerializer(itemClass);
if (serializer == null) {
serializer = new SerializerBuilder(((Marshaller)ctx).getJsonbContext()).withObjectClass(itemClass).withWrapper(this).withModel(model).build();
addValueSerializer(serializer, itemClass);
}
serializerCaptor(serializer, item, generator, ctx);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@

package org.eclipse.yasson.internal.serializer;

import org.eclipse.yasson.internal.JsonbContext;
import org.eclipse.yasson.internal.Marshaller;
import org.eclipse.yasson.internal.ReflectionUtils;
import org.eclipse.yasson.internal.model.JsonBindingModel;

import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
import javax.json.stream.JsonGenerator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Optional;

/**
* Serializer for collections.
Expand All @@ -35,26 +31,10 @@ public class CollectionSerializer<T extends Collection> extends AbstractContaine

private final JsonBindingModel containerModel;

private final Type collectionValueType;

private final JsonbSerializer valueSerializer;

protected CollectionSerializer(SerializerBuilder builder) {
super(builder);
collectionValueType = getValueType();
Type collectionValueType = getValueType();
containerModel = new ContainerModel(collectionValueType, resolveContainerModelCustomization(collectionValueType, builder.getJsonbContext()));
valueSerializer = resolveValueSerializer(collectionValueType, builder.getJsonbContext());
}

private JsonbSerializer resolveValueSerializer(Type collectionValueType, JsonbContext jsonbContext) {
if (collectionValueType == Object.class) {
return null;
}
final Optional<Class<?>> optionalRawType = ReflectionUtils.getOptionalRawType(collectionValueType);
if (!optionalRawType.isPresent()) {
return null;
}
return new SerializerBuilder(jsonbContext).withType(collectionValueType).withObjectClass(optionalRawType.get()).withWrapper(this).withModel(containerModel).build();
}

private Type getValueType() {
Expand All @@ -66,16 +46,7 @@ private Type getValueType() {
@Override
protected void serializeInternal(T collection, JsonGenerator generator, SerializationContext ctx) {
for (Object item : collection) {
if (item == null) {
generator.writeNull();
continue;
}
if (valueSerializer != null) {
serializerCaptor(valueSerializer, item, generator, ctx);
} else {
final JsonbSerializer<?> serializer = new SerializerBuilder(((Marshaller)ctx).getJsonbContext()).withObjectClass(item.getClass()).withWrapper(this).withModel(containerModel).build();
serializerCaptor(serializer, item, generator, ctx);
}
serializeItem(item, generator, ctx, containerModel);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import org.eclipse.yasson.internal.Marshaller;
import org.eclipse.yasson.internal.ReflectionUtils;
import org.eclipse.yasson.internal.model.JsonBindingModel;

import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
Expand All @@ -28,49 +29,32 @@
*
* @author Roman Grigoriadi
*/
public class MapSerializer<T extends Map> extends AbstractContainerSerializer<T> implements EmbeddedItem {
public class MapSerializer<T extends Map<?,?>> extends AbstractContainerSerializer<T> implements EmbeddedItem {

private Type mapValueRuntimeType;

private final JsonbSerializer<?> valueSerializer;
private final JsonBindingModel containerModel;

protected MapSerializer(SerializerBuilder builder) {
super(builder);
mapValueRuntimeType = getRuntimeType() instanceof ParameterizedType ?
Type mapValueRuntimeType = getRuntimeType() instanceof ParameterizedType ?
ReflectionUtils.resolveType(this, ((ParameterizedType) getRuntimeType()).getActualTypeArguments()[1])
: Object.class;

//Lets try to cache value serializer, runtime type must be unambiguous
Class<?> valueClass = ReflectionUtils.getRawType(mapValueRuntimeType);
if (valueClass == Object.class) {
valueSerializer = null;
return;
}

valueSerializer = new SerializerBuilder(builder.getJsonbContext()).withObjectClass(valueClass)
.withModel(new ContainerModel(mapValueRuntimeType,
resolveContainerModelCustomization(mapValueRuntimeType, builder.getJsonbContext()))).build();
containerModel = new ContainerModel(mapValueRuntimeType,
resolveContainerModelCustomization(mapValueRuntimeType, builder.getJsonbContext()));
}

@Override
protected void serializeInternal(T obj, JsonGenerator generator, SerializationContext ctx) {
final Marshaller marshaller = (Marshaller) ctx;
obj.keySet().forEach((key) -> {
final String keysString = String.valueOf(key);
final Object value = obj.get(key);
for (Map.Entry<?,?> entry : obj.entrySet()) {
final String keysString = String.valueOf(entry.getKey());
final Object value = entry.getValue();
if (value == null) {
generator.writeNull(keysString);
return;
}
generator.writeKey(keysString);
JsonbSerializer<?> serializer = valueSerializer;
if (serializer == null) {
serializer = new SerializerBuilder(marshaller.getJsonbContext()).withObjectClass(value.getClass())
.withModel(new ContainerModel(mapValueRuntimeType,
resolveContainerModelCustomization(mapValueRuntimeType, marshaller.getJsonbContext()))).build();
}
serializerCaptor(serializer, value, generator, ctx);
});
serializeItem(value, generator, ctx, containerModel);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@

package org.eclipse.yasson.internal.serializer;

import org.eclipse.yasson.internal.Marshaller;

import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
import javax.json.stream.JsonGenerator;

Expand All @@ -33,17 +30,7 @@ protected ObjectArraySerializer(SerializerBuilder builder) {
@Override
protected void serializeInternal(T[] arr, JsonGenerator generator, SerializationContext ctx) {
for (T obj : arr) {
if (obj == null) {
generator.writeNull();
continue;
}
final JsonbSerializer<?> serializer = new SerializerBuilder(((Marshaller) ctx)
.getJsonbContext())
.withObjectClass(obj.getClass())
.withWrapper(this)
.withModel(containerModel)
.build();
serializerCaptor(serializer, obj, generator, ctx);
serializeItem(obj, generator, ctx, containerModel);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ public void testMarshallMap() {
assertEquals(stringIntegerMap, jsonb.fromJson("{\"1\":1,\"2\":2,\"3\":3}", new LinkedHashMap<String, Integer>(){}.getClass().getGenericSuperclass()));
}

@Test
public void testListOfNumbers() {
List<Number> numberList = new ArrayList<>();
numberList.add(1L);
numberList.add(2f);
numberList.add(10);

String result = jsonb.toJson(numberList, new TestTypeToken<List<Number>>(){}.getType());
}

@Test
public void testListOfListsOfStrings() {

Expand Down

0 comments on commit a2a767f

Please sign in to comment.