Skip to content

Commit

Permalink
Fixes #57
Browse files Browse the repository at this point in the history
Adapters, Serializers and Deserializers bound to properties were cached globally per type.
Deserialization of JsonString, JsonNumber and JsonArray into JsonValue interface.

Signed-off-by: Roman Grigoriadi <roman.grigoriadi@oracle.com>
  • Loading branch information
Roman Grigoriadi committed Oct 27, 2017
1 parent 1070c5c commit c835156
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 27 deletions.
21 changes: 9 additions & 12 deletions src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,19 @@ private interface ComponentSupplier<T extends AbstractComponentBinding> {
void init() {
final JsonbSerializer<?>[] serializers = (JsonbSerializer<?>[])jsonbContext.getConfig().getProperty(JsonbConfig.SERIALIZERS).orElseGet(()->new JsonbSerializer<?>[]{});
for (JsonbSerializer serializer : serializers) {
introspectSerializerBinding(serializer.getClass(), serializer);
SerializerBinding serializerBinding = introspectSerializerBinding(serializer.getClass(), serializer);
addSerializer(serializerBinding.getBindingType(), serializerBinding);
}
final JsonbDeserializer<?>[] deserializers = (JsonbDeserializer<?>[])jsonbContext.getConfig().getProperty(JsonbConfig.DESERIALIZERS).orElseGet(()->new JsonbDeserializer<?>[]{});
for (JsonbDeserializer deserializer : deserializers) {
introspectDeserializerBinding(deserializer.getClass(), deserializer);
DeserializerBinding deserializerBinding = introspectDeserializerBinding(deserializer.getClass(), deserializer);
addDeserializer(deserializerBinding.getBindingType(), deserializerBinding);
}

final JsonbAdapter<?, ?>[] adapters = (JsonbAdapter<?, ?>[]) jsonbContext.getConfig().getProperty(JsonbConfig.ADAPTERS).orElseGet(()->new JsonbAdapter<?, ?>[]{});
for (JsonbAdapter<?, ?> adapter : adapters) {
introspectAdapterBinding(adapter.getClass(), adapter);
AdapterBinding adapterBinding = introspectAdapterBinding(adapter.getClass(), adapter);
addAdapter(adapterBinding.getBindingType(), adapterBinding);
}
}

Expand Down Expand Up @@ -239,9 +242,7 @@ AdapterBinding introspectAdapterBinding(Class<? extends JsonbAdapter> adapterCla
return componentBindings.getAdapterInfo();
}
JsonbAdapter newAdapter = instance != null ? instance : jsonbContext.getComponentInstanceCreator().getOrCreateComponent(adapterClass);
final AdapterBinding adapterInfo = new AdapterBinding(adaptFromType, adaptToType, newAdapter);
addAdapter(adaptFromType, adapterInfo);
return adapterInfo;
return new AdapterBinding(adaptFromType, adaptToType, newAdapter);
}

/**
Expand All @@ -261,9 +262,7 @@ DeserializerBinding introspectDeserializerBinding(Class<? extends JsonbDeseriali
} else {
JsonbDeserializer deserializer = instance != null ? instance : jsonbContext.getComponentInstanceCreator()
.getOrCreateComponent(deserializerClass);
final DeserializerBinding deserializerBinding = new DeserializerBinding(deserializerBindingType, deserializer);
addDeserializer(deserializerBindingType, deserializerBinding);
return deserializerBinding;
return new DeserializerBinding(deserializerBindingType, deserializer);
}
}

Expand All @@ -284,9 +283,7 @@ SerializerBinding introspectSerializerBinding(Class<? extends JsonbSerializer> s
} else {
JsonbSerializer serializer = instance != null ? instance : jsonbContext.getComponentInstanceCreator()
.getOrCreateComponent(serializerClass);
final SerializerBinding serializerBinding = new SerializerBinding(serBindingType, serializer);
addSerializer(serBindingType, serializerBinding);
return serializerBinding;
return new SerializerBinding(serBindingType, serializer);
}

}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/eclipse/yasson/internal/JsonbRiParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -311,4 +311,8 @@ public void skipObject() {
jsonParser.skipObject();
level.pop();
}

public JsonParser.Event getLastEvent() {
return level.peek().getLastEvent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
import java.util.OptionalLong;

/**
* Base class for all deserializers.
* Base class for all deserializers producing non single value result.
* Deserialize bean objects, collections, maps, arrays, etc.
*
* @author Roman Grigoriadi
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*/
public class AdaptedObjectDeserializer<A, T> implements CurrentItem<T>, JsonbDeserializer<T> {

private JsonbDeserializer<A> adaptedItem;
private JsonbDeserializer<A> adaptedTypeDeserializer;

private final AdapterBinding adapterInfo;

Expand Down Expand Up @@ -65,24 +65,24 @@ public CurrentItem<?> getWrapper() {

@Override
public JsonBindingModel getWrapperModel() {
return ((AbstractContainerDeserializer) adaptedItem).getWrapperModel();
return ((AbstractContainerDeserializer) adaptedTypeDeserializer).getWrapperModel();
}

@Override
public Type getRuntimeType() {
if (adaptedItem instanceof AbstractContainerDeserializer) {
return ((AbstractContainerDeserializer) adaptedItem).getRuntimeType();
if (adaptedTypeDeserializer instanceof AbstractContainerDeserializer) {
return ((AbstractContainerDeserializer) adaptedTypeDeserializer).getRuntimeType();
}
throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Deserialization propagation is not allowed for:" + adaptedItem));
throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Deserialization propagation is not allowed for:" + adaptedTypeDeserializer));
}

/**
* Sets adapted item.
*
* @param adaptedItem Adapted item to set.
* @param adaptedTypeDeserializer Adapted item to set.
*/
public void setAdaptedItem(JsonbDeserializer<A> adaptedItem) {
this.adaptedItem = adaptedItem;
public void setAdaptedTypeDeserializer(JsonbDeserializer<A> adaptedTypeDeserializer) {
this.adaptedTypeDeserializer = adaptedTypeDeserializer;
}

@Override
Expand All @@ -91,7 +91,7 @@ public T deserialize(JsonParser parser, DeserializationContext context, Type rtT
unmarshaller.setCurrent(this);
try {
unmarshaller.getJsonbContext().addProcessedType(adapterInfo.getBindingType());
final A result = adaptedItem.deserialize(parser, context, rtType);
final A result = adaptedTypeDeserializer.deserialize(parser, context, rtType);
final T adapted = ((JsonbAdapter<T, A>) adapterInfo.getAdapter()).adaptFromJson(result);
unmarshaller.setCurrent(wrapperItem);
return adapted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public JsonbDeserializer<?> build() {

JsonbDeserializer<?> deserializer;
if (jsonEvent == JsonParser.Event.START_ARRAY) {
if (JsonStructure.class.isAssignableFrom(rawType)) {
if (JsonValue.class.isAssignableFrom(rawType)) {
return wrapAdapted(adapterInfoOptional, new JsonArrayDeserializer(this));
} else if (rawType.isArray() || getRuntimeType() instanceof GenericArrayType) {
deserializer = createArrayItem(rawType.getComponentType());
Expand Down Expand Up @@ -189,7 +189,7 @@ private JsonbDeserializer<?> wrapAdapted(Optional<AdapterBinding> adapterInfoOpt
}

private <T,A> void setAdaptedItemCaptor(AdaptedObjectDeserializer<T,A> decoratorItem, JsonbDeserializer<T> adaptedItem) {
decoratorItem.setAdaptedItem(adaptedItem);
decoratorItem.setAdaptedTypeDeserializer(adaptedItem);
}

private Type resolveRuntimeType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@

package org.eclipse.yasson.internal.serializer;

import org.eclipse.yasson.internal.JsonbRiParser;
import org.eclipse.yasson.internal.Unmarshaller;
import org.eclipse.yasson.internal.properties.MessageKeys;
import org.eclipse.yasson.internal.properties.Messages;
import org.eclipse.yasson.internal.model.JsonBindingModel;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import javax.json.bind.JsonbException;
import javax.json.bind.serializer.DeserializationContext;
import javax.json.stream.JsonParser;
import java.lang.reflect.Type;

/**
* Deserializer for {@link JsonValue} containing null, false and true.
* Deserializer for {@link JsonValue} containing null, false, true, string and number.
*
* @author Roman Grigoriadi
*/
Expand All @@ -42,14 +45,17 @@ public JsonValueDeserializer(JsonBindingModel model) {

@Override
public JsonValue deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
final JsonParser.Event next = parser.next();
final JsonParser.Event next = ((JsonbRiParser)parser).getLastEvent();
switch (next) {
case VALUE_TRUE:
return JsonValue.TRUE;
case VALUE_FALSE:
return JsonValue.FALSE;
case VALUE_NULL:
return JsonValue.NULL;
case VALUE_STRING:
case VALUE_NUMBER:
return parser.getValue();
default:
throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Unknown JSON value: "+next));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,18 @@ public T getInstance(Unmarshaller unmarshaller) {
@Override
public void deserializeInternal(JsonbParser parser, Unmarshaller context) {
parserContext = moveToFirst(parser);
JsonParser.Event lastEvent = parserContext.getLastEvent();
final UserDeserializerParser userDeserializerParser = new UserDeserializerParser(parser);
try {
context.getJsonbContext().addProcessedType(deserializerBinding.getBindingType());
deserializerResult = (T) deserializerBinding.getJsonbDeserializer().deserialize(userDeserializerParser, context, getRuntimeType());
} finally {
context.getJsonbContext().removeProcessedType(deserializerBinding.getBindingType());
}
userDeserializerParser.advanceParserToEnd();
//Avoid moving parser to the end of the object, if deserializer was for one value only.
if (lastEvent == JsonParser.Event.START_ARRAY || lastEvent == JsonParser.Event.START_OBJECT) {
userDeserializerParser.advanceParserToEnd();
}
}

@Override
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/org/eclipse/yasson/adapters/AdaptersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.yasson.TestTypeToken;
import org.eclipse.yasson.adapters.model.*;
import org.junit.Assert;
import org.junit.Test;

import javax.json.bind.Jsonb;
Expand Down Expand Up @@ -404,4 +405,18 @@ public void testAdaptJsonObject() {
assertEquals("strFieldValue", result.box.getBoxStrField());
assertEquals(Integer.valueOf(110), result.box.getBoxIntegerField());
}

@Test
public void testAdaptAuthor() {
Author author = new Author();
author.setFirstName("John");
author.setLastName("Connor");

Jsonb jsonb = JsonbBuilder.create();
String json = jsonb.toJson(author);
Assert.assertEquals("{\"firstName\":\"J\",\"lastName\":\"Connor\"}", json);

Author result = jsonb.fromJson("{\"firstName\":\"J\",\"lastName\":\"Connor\"}", Author.class);
System.out.println(result);
}
}
25 changes: 25 additions & 0 deletions src/test/java/org/eclipse/yasson/adapters/model/Author.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.eclipse.yasson.adapters.model;

import javax.json.bind.annotation.JsonbTypeAdapter;

public class Author {
@JsonbTypeAdapter(FirstNameAdapter.class)
private String firstName;
private String lastName;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.eclipse.yasson.adapters.model;

import javax.json.Json;
import javax.json.JsonValue;
import javax.json.bind.adapter.JsonbAdapter;

public class FirstNameAdapter implements JsonbAdapter<String, JsonValue> {
@Override
public JsonValue adaptToJson(String firstName) {
return Json.createValue(firstName.subSequence(0,1).toString());
}
@Override
public String adaptFromJson(JsonValue json) {
return json.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,50 @@ public void testJsonObjectAsValue() {
assertEquals("Test String", ((JsonObject) jsonValueWrapper.jsonValue).getString("stringInstance"));
}

@Test
public void testJsonValueString() {
JsonValueWrapper pojo = new JsonValueWrapper(Json.createValue("abc"));
String json = jsonb.toJson(pojo);
Assert.assertEquals("{\"jsonValue\":\"abc\"}", json);

JsonValueWrapper result = jsonb.fromJson("{\"jsonValue\":\"def\"}", JsonValueWrapper.class);
Assert.assertTrue(result.jsonValue instanceof JsonString);
Assert.assertEquals("def", ((JsonString)result.jsonValue).getString());
}

@Test
public void testJsonValueAsObject() {
JsonObject build = Json.createObjectBuilder().add("prop1", "val1")
.add("prop2", "val2")
.add("innerObj1", Json.createObjectBuilder().add("inner1", "innerVal1").build())
.build();
JsonValueWrapper pojo = new JsonValueWrapper(build);
String expected = "{\"jsonValue\":{\"prop1\":\"val1\",\"prop2\":\"val2\",\"innerObj1\":{\"inner1\":\"innerVal1\"}}}";
String json = jsonb.toJson(pojo);
Assert.assertEquals(expected, json);

JsonValueWrapper result = jsonb.fromJson(expected, JsonValueWrapper.class);
Assert.assertTrue(result.jsonValue instanceof JsonObject);
JsonObject jsonObject = (JsonObject) result.jsonValue;
Assert.assertEquals("val1", jsonObject.getString("prop1"));
Assert.assertEquals("innerVal1", jsonObject.getJsonObject("innerObj1").getString("inner1"));
}

@Test
public void testJsonValueAsArray() {
JsonArray jsonArray = Json.createArrayBuilder().add(1).add(2).add(3).add(Json.createObjectBuilder().add("a","b").build()).build();
JsonValueWrapper pojo = new JsonValueWrapper(jsonArray);
String expected = "{\"jsonValue\":[1,2,3,{\"a\":\"b\"}]}";
String json = jsonb.toJson(pojo);
Assert.assertEquals(expected, json);

JsonValueWrapper result = jsonb.fromJson(expected, JsonValueWrapper.class);
Assert.assertTrue(result.jsonValue instanceof JsonArray);
JsonArray resultArray = (JsonArray) result.jsonValue;
Assert.assertEquals(1, resultArray.getInt(0));
Assert.assertEquals(2, resultArray.getInt(1));
Assert.assertEquals(3, resultArray.getInt(2));
Assert.assertEquals("b", resultArray.getJsonObject(3).getString("a"));

}
}
15 changes: 15 additions & 0 deletions src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.junit.Assert;
import org.junit.Test;

import javax.json.JsonBuilderFactory;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
Expand Down Expand Up @@ -260,6 +261,20 @@ public void testRecursiveSerializer() {
Assert.assertEquals("Box to deserialize", result.boxStr);
}

@Test
public void testAuthor() {
Author author = new Author("Sarah", "Connor");
Jsonb jsonb = JsonbBuilder.create();
String expected = "{\"firstName\":\"S\",\"lastName\":\"Connor\"}";
String json = jsonb.toJson(author);

Assert.assertEquals(expected, json);

Author result = jsonb.fromJson(expected, Author.class);
Assert.assertEquals("John", result.getFirstName());
Assert.assertEquals("Connor", result.getLastName());
}

private Box createPojoWithDates() {
Date date = getExpectedDate();
Box box = createPojo();
Expand Down

0 comments on commit c835156

Please sign in to comment.