-
-
Save msamujlo/474dfab4b0f1368395e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.core.JsonParser; | |
import com.fasterxml.jackson.core.JsonProcessingException; | |
import com.fasterxml.jackson.core.Version; | |
import com.fasterxml.jackson.databind.*; | |
import com.fasterxml.jackson.databind.deser.Deserializers; | |
import com.fasterxml.jackson.databind.node.ObjectNode; | |
import java.io.IOException; | |
import java.util.Iterator; | |
/** | |
* @author Ben Fagin | |
* @version 2013-12-13 | |
*/ | |
public class MapperModule extends Module { | |
@Override | |
public String getModuleName() { | |
return "ModelMapper"; | |
} | |
@Override | |
public Version version() { | |
return new Version(2, 0, 0, null, null, null); | |
} | |
@Override | |
public void setupModule(SetupContext context) { | |
context.addDeserializers(new Deserializers.Base() { | |
public @Override JsonDeserializer<?> findBeanDeserializer(final JavaType type, DeserializationConfig config, BeanDescription beanDesc) throws JsonMappingException { | |
if (Model.class.isAssignableFrom(type.getRawClass())) { | |
return new JsonDeserializer<Object>() { | |
public @Override Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { | |
Iterator<ObjectNode> obj = jp.readValuesAs(ObjectNode.class); | |
return ModelMapper.map(type.getRawClass(), obj.next()); | |
} | |
}; | |
} | |
return super.findBeanDeserializer(type, config, beanDesc); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Marker interface for all model objects. | |
* | |
* @author Ben Fagin | |
* @version 2013-12-13 | |
*/ | |
interface Model { | |
// nothing here, as this is just a marker | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.databind.*; | |
import com.fasterxml.jackson.databind.node.ObjectNode; | |
import com.fasterxml.jackson.databind.node.POJONode; | |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
import static com.google.common.base.Preconditions.checkArgument; | |
import static com.google.common.base.Preconditions.checkNotNull; | |
/** | |
* @author Ben Fagin | |
* @version 2013-12-13 | |
*/ | |
public class ModelMapper { | |
@SuppressWarnings("unchecked") | |
public static <T> T map(Class<T> klaus, final ObjectNode data) { | |
checkNotNull(data); | |
checkArgument(klaus != null && klaus.isInterface(), "interfaces only please"); | |
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{klaus}, new InvocationHandler() { | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
String property = method.getName().substring(3); | |
property = new String(new char[]{property.charAt(0)}).toLowerCase() + property.substring(1); | |
// getter | |
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { | |
return getProperty(data, property, method); | |
} | |
// setter | |
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { | |
data.putPOJO(property, args[0]); | |
return null; | |
} | |
throw new RuntimeException("Not a property: "+method.getName()); | |
} | |
}); | |
} | |
private static Object getProperty(ObjectNode data, String property, Method method) { | |
Class<?> returnType = method.getReturnType(); | |
JsonNode value = data.get(property); | |
if (Integer.class.equals(returnType) || int.class.equals(returnType)) { | |
return value.asInt(); | |
} | |
else if (Double.class.equals(returnType) || double.class.equals(returnType)) { | |
return value.asDouble(); | |
} | |
else if (Long.class.equals(returnType) || long.class.equals(returnType)) { | |
return value.asLong(); | |
} | |
else if (Boolean.class.equals(returnType) || boolean.class.equals(returnType)) { | |
return value.asBoolean(); | |
} | |
else if (String.class.equals(returnType)) { | |
return value.asText(); | |
} | |
else if (returnType.isInterface() && Model.class.isAssignableFrom(returnType)) { | |
if (value.isObject()) { | |
return map(returnType, (ObjectNode) value); | |
} else if (value.isPojo()) { | |
return ((POJONode) value).getPojo(); | |
} | |
} | |
throw new RuntimeException("Unknown return type: "+returnType); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.databind.ObjectMapper; | |
import com.fasterxml.jackson.databind.node.ObjectNode; | |
import java.io.ByteArrayOutputStream; | |
/** | |
* @author Ben Fagin | |
* @version 2013-12-13 | |
*/ | |
public class Test { | |
interface Point extends Model { | |
int getX(); | |
void setX(int x); | |
int getY(); | |
void setY(int y); | |
Nub getNub(); | |
void setNub(Nub nub); | |
} | |
interface Nub extends Model { | |
void setThing(int thing); | |
int getThing(); | |
} | |
public static void main(String[] args) throws Exception { | |
final ObjectMapper jsonMapper = new ObjectMapper(); | |
jsonMapper.registerModule(new MapperModule()); | |
ObjectNode data = jsonMapper.createObjectNode(); | |
data.put("x", 100); | |
data.put("y", 200); | |
data.putObject("nub").put("thing", 300); | |
Point point = jsonMapper.reader(Point.class).readValue(data); | |
System.out.println(point.getX()); | |
System.out.println(point.getY()); | |
System.out.println(point.getNub().getThing()); | |
point.setX(111); | |
point.setY(222); | |
point.setNub(new Nub() { | |
int val = 333; | |
public void setThing(int thing) { | |
val = thing; | |
} | |
public int getThing() { | |
return val; | |
} | |
}); | |
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |
System.out.println(point.getX()); | |
System.out.println(point.getY()); | |
System.out.println(point.getNub().getThing()); | |
jsonMapper.writerWithType(Point.class).writeValue(os, point); | |
System.out.println(os.toString()); | |
os.reset(); | |
point.getNub().setThing(400); | |
System.out.println(point.getNub().getThing()); | |
jsonMapper.writerWithType(Point.class).writeValue(os, point); | |
System.out.println(os.toString()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment