Skip to content

Commit

Permalink
added class json attribute support in number of cases, notably abstra…
Browse files Browse the repository at this point in the history
…ct classes within Map and List
  • Loading branch information
Dominik Smogor committed Aug 22, 2017
1 parent 9bc6870 commit fe5e4f0
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ private static Annotation[] extractAllAnnotationsForProperty( Class<?> clazz, St
/* In the land of dynamic proxied AOP classes,
* this class could be a proxy. This seems like a bug
* waiting to happen. So far it has worked... */
if ( annotations.length == 0 ) {
if ( annotations.length == 0 && clazz.getSuperclass() != null) {
annotations = findPropertyAnnotations( clazz.getSuperclass(), propertyName, useRead );
}
return annotations;
Expand Down
24 changes: 18 additions & 6 deletions boon/src/main/java/org/boon/core/reflection/MapperComplex.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,15 @@ public <T> List<T> convertListOfMapsToObjects(List<Map> list, Class<T> componen
/**
* fromMap converts a map into a java object
* @param map map to create the object from.
* @param cls class type of new object
* @param c class type of new object
* @param <T> map to create teh object from.
* @return new object of type cls <T>
*/
@Override
public <T> T fromMap(final Map<String, Object> map, final Class<T> cls) {
public <T> T fromMap(final Map<String, Object> map, final Class<T> c) {


final Class<T> cls = MapperSimple.handleAbstractReplacement(map, c);
T toObject = Reflection.newInstance( cls );
Map<String, FieldAccess> fields = fieldsAccessor.getFields( toObject.getClass() );
Set<Map.Entry<String, Object>> mapKeyValuesEntrySet = map.entrySet();
Expand Down Expand Up @@ -1171,14 +1172,15 @@ public Object fromValueMap(final Map<String, Value> valueMap
* This does some special handling to take advantage of us using the value map so it avoids creating
* a bunch of array objects and collections. Things you have to worry about when writing a
* high-speed JSON serializer.
* @param cls the new type
* @param c the new type
* @return new object from value map
*/
@Override
@SuppressWarnings("unchecked")
public <T> T fromValueMap(final Map<String, Value> valueMap,
final Class<T> cls) {
final Class<T> c) {

final Class<T> cls = MapperSimple.handleAbstractReplacement(valueMap, c);
T newInstance = Reflection.newInstance( cls );
ValueMap map = ( ValueMap ) ( Map ) valueMap;

Expand Down Expand Up @@ -1372,8 +1374,18 @@ private <T> void fromValueMapHandleValueCase(
evalue = ((ValueContainer) evalue).toValue();
}



key = Conversions.coerce( keyType, key );
evalue = Conversions.coerce( valueType, evalue );


Class actualType = valueType;
if ( valueType.isInterface() || Typ.isAbstract( valueType ) && evalue instanceof Map && ((Map)evalue).containsKey("class")) {
String className = ((Map)evalue)
.get("class").toString();
actualType = Reflection.loadClass( className );
}
evalue = Conversions.coerce( actualType, evalue );
newMap.put( key, evalue );
}

Expand Down Expand Up @@ -1842,4 +1854,4 @@ public List<?> toList(Object object) {
}


}
}
59 changes: 44 additions & 15 deletions boon/src/main/java/org/boon/core/reflection/MapperSimple.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,36 @@ public <T> List<T> convertListOfMapsToObjects(List<Map> list, Class<T> componen
return ( List<T> ) newList;
}

static <T> Class<T> handleAbstractReplacement(final Map<String, ?> map, final Class<T> cls) {
if (cls.isInterface() && Typ.isAbstract(cls)) {
if(map.containsKey("class")) {
String className = map.get("class").toString();
if (className != null) {
Class c = Reflection.loadClass(className);
if (cls.isAssignableFrom(c)) {
return c;
}
}

}
}
return cls;

}

/**
* fromMap converts a map into a java object
* @param map map to create the object from.
* @param cls class type of new object
* @param <T> map to create teh object from.
* @return new object of type cls <T>
*/
@Override
public <T> T fromMap(final Map<String, Object> map, final Class<T> cls) {




/**
* fromMap converts a map into a java object
* @param map map to create the object from.
* @param <T> map to create teh object from.
* @return new object of type cls <T>
*/
@Override
public <T> T fromMap(final Map<String, Object> map, final Class<T> c) {
final Class<T> cls = handleAbstractReplacement(map, c);
T toObject = Reflection.newInstance( cls );
Map<String, FieldAccess> fields = fieldsAccessor.getFields( toObject.getClass() );
Set<Map.Entry<String, Object>> mapKeyValuesEntrySet = map.entrySet();
Expand Down Expand Up @@ -1042,8 +1059,7 @@ private void handleCollectionOfValues(
*/
@Override
@SuppressWarnings("unchecked")
public Object fromValueMap(final Map<String, Value> valueMap
) {
public Object fromValueMap(final Map<String, Value> valueMap) {


try {
Expand All @@ -1063,14 +1079,15 @@ public Object fromValueMap(final Map<String, Value> valueMap
* This does some special handling to take advantage of us using the value map so it avoids creating
* a bunch of array objects and collections. Things you have to worry about when writing a
* high-speed JSON serializer.
* @param cls the new type
* @param c the new type
* @return new object from value map
*/
@Override
@SuppressWarnings("unchecked")
public <T> T fromValueMap(final Map<String, Value> valueMap,
final Class<T> cls) {
final Class<T> c) {

final Class<T> cls = handleAbstractReplacement(valueMap, c);
T newInstance = Reflection.newInstance( cls );
ValueMap map = ( ValueMap ) ( Map ) valueMap;

Expand Down Expand Up @@ -1259,7 +1276,13 @@ private <T> void fromValueMapHandleValueCase(
}

key = Conversions.coerce( keyType, key );
evalue = Conversions.coerce( valueType, evalue );
Class actualType = valueType;
if ( valueType.isInterface() || Typ.isAbstract( valueType ) && evalue instanceof Map && ((Map)evalue).containsKey("class")) {
String className = ((Map)evalue)
.get("class").toString();
actualType = Reflection.loadClass( className );
}
evalue = Conversions.coerce( actualType, evalue );
newMap.put( key, evalue );
}

Expand Down Expand Up @@ -1352,7 +1375,13 @@ private void setFieldValueFromMap( final Object parentObject,
}

key = Conversions.coerce(keyType, key);
evalue = Conversions.coerce( valueType, evalue );
Class actualType = valueType;
if ( valueType.isInterface() || Typ.isAbstract( valueType ) && evalue instanceof Map && ((Map)evalue).containsKey("class")) {
String className = ((Map)evalue)
.get("class").toString();
actualType = Reflection.loadClass( className );
}
evalue = Conversions.coerce( actualType, evalue );
newMap.put( key, evalue );
}

Expand Down
13 changes: 13 additions & 0 deletions boon/src/test/java/org/boon/json/code/InterfaceB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.boon.json.code;


/**
* Created by piyush.goyal on 9/22/16.
*/
public interface InterfaceB {

String getPiyush();

void setPiyush(String piyush);

}
88 changes: 88 additions & 0 deletions boon/src/test/java/org/boon/json/code/JsonAbstractClassesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.boon.json.code;

import org.boon.json.JsonFactory;
import org.boon.json.JsonParserFactory;
import org.boon.json.JsonSerializer;
import org.boon.json.JsonSerializerFactory;
import org.boon.json.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Created by piyush.goyal on 8/17/17.
*/
public class JsonAbstractClassesTest {



private ObjectMapper mapper;

@Test
public void testAbstracTClassesWSimpleMapper() {
mapper = JsonFactory.create(new JsonParserFactory().useAnnotations(),
new JsonSerializerFactory().useAnnotations());
testAbstracTClasses();
}
@Test
public void testAbstracTClassesWComplexMapper() {
mapper = JsonFactory.create(new JsonParserFactory().setRespectIgnore(false).useAnnotations(),
new JsonSerializerFactory().useAnnotations());
testAbstracTClasses();
}

public void testAbstracTClasses() {


JsonClassC c = new JsonClassC();
c.setPiyush("Tosheer");

JsonClassD d = new JsonClassD();
d.setPiyush("VIvek");

Map<String, InterfaceB> map = new HashMap<>();
map.put("c", c);
map.put("d", d);

List<InterfaceB> list = new ArrayList<>();
list.add(c);
list.add(d);

JsonClassA jsonClassA = new JsonClassA();

jsonClassA.setTextValue("aa");
jsonClassA.setXx(map);
jsonClassA.setYy(list);

JsonSerializer serializer = new JsonSerializerFactory().setOutputType(true).create();

String s = serializer.serialize(jsonClassA).toString();
System.out.println(s);

//String json = "{\"class\":\"com.akqa.some.code.JsonClassA\",\"xx\":{\"c\":{\"class\":\"com.akqa.some.code.JsonClassC\",\"piyush\":\"Tosheer\"},\"d\":{\"class\":\"com.akqa.some.code.JsonClassD\",\"piyush\":\"VIvek\"}},\"textValue\":\"aa\"}";
String json = s;
JsonClassA jsonClassA1 = mapper.fromJson(json, JsonClassA.class);


assertEquals("aa", jsonClassA1.getTextValue());
Map<String, InterfaceB> xx = jsonClassA1.getXx();
InterfaceB c1 = xx.get("c");
InterfaceB d1 = xx.get("d");
assertEquals("Tosheer", c1.getPiyush());
assertEquals("VIvek", d1.getPiyush());
assertEquals(c.getClass(), c1.getClass());
assertEquals(d.getClass(), d1.getClass());
List<InterfaceB> list1= jsonClassA1.getYy();
c1 = list1.get(0);
d1 = list1.get(1);
assertEquals("Tosheer", c1.getPiyush());
assertEquals("VIvek", d1.getPiyush());
assertEquals(c.getClass(), c1.getClass());
assertEquals(d.getClass(), d1.getClass());
}
}
42 changes: 42 additions & 0 deletions boon/src/test/java/org/boon/json/code/JsonClassA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.boon.json.code;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Created by piyush.goyal on 9/22/16.
*/
public class JsonClassA {


private Map<String, InterfaceB> xx = new HashMap<>();

private List<InterfaceB> yy = new ArrayList<>();
private String textValue;

public String getTextValue() {
return textValue;
}

public void setTextValue(String textValue) {
this.textValue = textValue;
}

public Map<String, InterfaceB> getXx() {
return xx;
}

public void setXx(Map<String, InterfaceB> xx) {
this.xx = xx;
}

public List<InterfaceB> getYy() {
return yy;
}

public void setYy(List<InterfaceB> yy) {
this.yy = yy;
}
}
22 changes: 22 additions & 0 deletions boon/src/test/java/org/boon/json/code/JsonClassC.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.boon.json.code;

/**
* Created by piyush.goyal on 9/22/16.
*/
public class JsonClassC implements InterfaceB {

protected JsonClassC(){}


private String piyush;

@Override
public String getPiyush() {
return piyush;
}

@Override
public void setPiyush(String piyush) {
this.piyush = piyush;
}
}
19 changes: 19 additions & 0 deletions boon/src/test/java/org/boon/json/code/JsonClassD.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.boon.json.code;

/**
* Created by piyush.goyal on 9/22/16.
*/
public class JsonClassD implements InterfaceB {

private String piyush;

@Override
public String getPiyush() {
return piyush;
}

@Override
public void setPiyush(String piyush) {
this.piyush = piyush;
}
}

0 comments on commit fe5e4f0

Please sign in to comment.