Skip to content

Instantly share code, notes, and snippets.

@volgar1x
Created November 11, 2013 00:48
Show Gist options
  • Save volgar1x/7406042 to your computer and use it in GitHub Desktop.
Save volgar1x/7406042 to your computer and use it in GitHub Desktop.
package org.photon;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator;
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.type.CollectionType;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.LazyLoader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public final class Deserializers {
public static class ManyToOne extends JsonDeserializer<Object> {
private final AnnotatedMember member;
public ManyToOne(AnnotatedMember member) {
this.member = member;
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
JavaType jt;
if (member instanceof AnnotatedMethod) {
jt = ctx.constructType(((AnnotatedMethod) member).getGenericParameterType(0));
} else {
jt = ctx.constructType(member.getGenericType());
}
BeanDescription bd = ctx.getConfig().getClassIntrospector()
.forDeserializationWithBuilder(ctx.getConfig(), jt, ctx.getConfig());
String property = bd.getObjectIdInfo().getPropertyName();
AnnotatedMember member = null;
for (BeanPropertyDefinition bpd : bd.findProperties()) {
if (bpd.getName().equals(property)) {
member = bpd.getAccessor();
break;
}
}
if (member == null) throw new IllegalStateException(String.format("unknown property `%s' on `%s'", property, bd.getType()));
Object id = jp.readValueAs(member.getRawType());
final ReadableObjectId roi = ctx.findObjectId(id, new FakeObjectIdGenerator(bd.getBeanClass(), member));
if (roi.item != null) {
return roi.item;
} else {
return Enhancer.create(this.member.getRawType(), new LazyLoader() {
@Override
public Object loadObject() throws Exception {
return roi.item;
}
});
}
}
}
public static class OneToMany extends JsonDeserializer<List<Object>> {
private final AnnotatedMember member;
public OneToMany(AnnotatedMember member) {
this.member = member;
}
@Override
public List<Object> deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
JavaType jt;
if (member instanceof AnnotatedMethod) {
jt = ctx.constructType(((AnnotatedMethod) member).getGenericParameterType(0));
} else {
jt = ctx.constructType(member.getGenericType());
}
BeanDescription bd = ctx.getConfig().getClassIntrospector()
.forDeserializationWithBuilder(ctx.getConfig(), jt.getContentType(), ctx.getConfig());
String property = bd.getObjectIdInfo().getPropertyName();
AnnotatedMember member = null;
for (BeanPropertyDefinition bpd : bd.findProperties()) {
if (bpd.getName().equals(property)) {
member = bpd.getAccessor();
break;
}
}
if (member == null) throw new IllegalStateException(String.format("unknown property `%s' on `%s'", property, bd.getType()));
List<Object> res = new ArrayList<>();
JsonDeserializer<Object> des = ctx.findRootValueDeserializer(CollectionType.construct(
List.class, ctx.constructType(member.getRawType())));
for (Object id : (Iterable) des.deserialize(jp, ctx)) {
final ReadableObjectId roi = ctx.findObjectId(id,
new FakeObjectIdGenerator(bd.getBeanClass(), member));
if (roi.item != null) {
res.add(roi.item);
} else {
res.add(Enhancer.create(bd.getBeanClass(), new LazyLoader() {
@Override
public Object loadObject() throws Exception {
return roi.item;
}
}));
}
}
return res;
}
}
public static class FakeObjectIdGenerator extends ObjectIdGenerator<Object> {
private final Class<?> scope;
private final AnnotatedMember member;
public FakeObjectIdGenerator(Class<?> scope, AnnotatedMember member) {
this.scope = scope;
this.member = member;
}
@Override
public Class<?> getScope() {
return scope;
}
@Override
public boolean canUseFor(ObjectIdGenerator<?> gen) {
return gen.getScope() == this.getScope();
}
@Override
public ObjectIdGenerator<Object> forScope(Class<?> scope) {
return new FakeObjectIdGenerator(scope, member);
}
@Override
public ObjectIdGenerator<Object> newForSerialization(Object context) {
return this;
}
@Override
public IdKey key(Object key) {
return new IdKey(PropertyBasedObjectIdGenerator.class, scope, key);
}
@Override
public Object generateId(Object forPojo) {
return member.getValue(forPojo);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment