java: adds TemplateBuilder and ReflectionTemplateBUilder

This commit is contained in:
FURUHASHI Sadayuki 2010-12-01 20:38:58 +09:00
parent 461b147897
commit 0339db57f1
2 changed files with 173 additions and 53 deletions

View File

@ -19,13 +19,23 @@ package org.msgpack.template;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.Map;
import java.util.HashMap;
import org.msgpack.*; import org.msgpack.*;
public class ReflectionTemplateBuilder extends TemplateBuilder { public class ReflectionTemplateBuilder extends TemplateBuilder {
public ReflectionTemplateBuilder() { private static ReflectionTemplateBuilder instance;
public synchronized static ReflectionTemplateBuilder getInstance() {
if(instance == null) {
instance = new ReflectionTemplateBuilder();
}
return instance;
} }
public static abstract class ReflectionFieldEntry extends FieldEntry { private ReflectionTemplateBuilder() {
}
static abstract class ReflectionFieldEntry extends FieldEntry {
public ReflectionFieldEntry(FieldEntry e) { public ReflectionFieldEntry(FieldEntry e) {
super(e.getField(), e.getOption()); super(e.getField(), e.getOption());
} }
@ -41,41 +51,41 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class ObjectFieldEntry extends ReflectionFieldEntry { static class ObjectFieldEntry extends ReflectionFieldEntry {
public ObjectFieldEntry(FieldEntry e) { private Template template;
ObjectFieldEntry(FieldEntry e, Template template) {
super(e); super(e);
this.template = template;
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
// TODO: call template template.pack(pac, target);
pac.pack(target);
} }
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException { public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
// TODO: call template
Field f = getField(); Field f = getField();
Class<Object> type = (Class<Object>)f.getType(); Class<Object> type = (Class<Object>)f.getType();
Object fieldReference = f.get(target); Object fieldReference = f.get(target);
Object valueReference = obj.convert(type, fieldReference); Object valueReference = template.convert(obj, fieldReference);
if(valueReference != fieldReference) { if(valueReference != fieldReference) {
f.set(target, valueReference); f.set(target, valueReference);
} }
} }
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException { public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
// TODO: call template
Field f = getField(); Field f = getField();
Class<Object> type = (Class<Object>)f.getType(); Class<Object> type = (Class<Object>)f.getType();
Object fieldReference = f.get(target); Object fieldReference = f.get(target);
Object valueReference = pac.unpack(type, fieldReference); Object valueReference = template.unpack(pac, fieldReference);
if(valueReference != fieldReference) { if(valueReference != fieldReference) {
f.set(target, valueReference); f.set(target, valueReference);
} }
} }
} }
public static class BooleanFieldEntry extends ReflectionFieldEntry { static class BooleanFieldEntry extends ReflectionFieldEntry {
public BooleanFieldEntry(FieldEntry e) { BooleanFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -89,8 +99,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class ByteFieldEntry extends ReflectionFieldEntry { static class ByteFieldEntry extends ReflectionFieldEntry {
public ByteFieldEntry(FieldEntry e) { ByteFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -104,8 +114,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class ShortFieldEntry extends ReflectionFieldEntry { static class ShortFieldEntry extends ReflectionFieldEntry {
public ShortFieldEntry(FieldEntry e) { ShortFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -119,8 +129,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class IntFieldEntry extends ReflectionFieldEntry { static class IntFieldEntry extends ReflectionFieldEntry {
public IntFieldEntry(FieldEntry e) { IntFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -134,8 +144,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class LongFieldEntry extends ReflectionFieldEntry { static class LongFieldEntry extends ReflectionFieldEntry {
public LongFieldEntry(FieldEntry e) { LongFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -149,8 +159,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class FloatFieldEntry extends ReflectionFieldEntry { static class FloatFieldEntry extends ReflectionFieldEntry {
public FloatFieldEntry(FieldEntry e) { FloatFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -164,8 +174,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
public static class DoubleFieldEntry extends ReflectionFieldEntry { static class DoubleFieldEntry extends ReflectionFieldEntry {
public DoubleFieldEntry(FieldEntry e) { DoubleFieldEntry(FieldEntry e) {
super(e); super(e);
} }
public void pack(Object target, Packer pac) throws IOException { public void pack(Object target, Packer pac) throws IOException {
@ -179,17 +189,19 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
} }
private static class ReflectionTemplate extends AbstractTemplate { static class ReflectionTemplate extends AbstractTemplate {
private Class<?> targetClass; protected Class<?> targetClass;
private ReflectionFieldEntry[] entries; protected ReflectionFieldEntry[] entries;
private int minimumArrayLength; protected int minimumArrayLength;
public ReflectionTemplate(Class<?> targetClass, ReflectionFieldEntry[] entries) { ReflectionTemplate(Class<?> targetClass, ReflectionFieldEntry[] entries) {
this.targetClass = targetClass; this.targetClass = targetClass;
this.entries = entries; this.entries = entries;
this.minimumArrayLength = 0;
for(int i=0; i < entries.length; i++) { for(int i=0; i < entries.length; i++) {
if(entries[i].isRequired() || entries[i].isNullable()) { ReflectionFieldEntry e = entries[i];
minimumArrayLength = i+1; if(e.isRequired() || e.isNullable()) {
this.minimumArrayLength = i+1;
} }
} }
} }
@ -209,9 +221,12 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} }
pk.packNil(); pk.packNil();
} else { } else {
pk.pack(obj); // TODO: call template e.pack(obj, pk);
} }
} }
} catch (MessageTypeException e) {
throw e;
} catch (IOException e) { } catch (IOException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -233,31 +248,40 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
int i; int i;
for(i=0; i < minimumArrayLength; i++) { for(i=0; i < minimumArrayLength; i++) {
ReflectionFieldEntry e = entries[i]; ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
pac.unpackObject();
continue;
}
if(pac.tryUnpackNull()) { if(pac.tryUnpackNull()) {
if(e.isRequired()) { if(e.isRequired()) {
// Requred + nil => exception // Requred + nil => exception
throw new MessageTypeException(); throw new MessageTypeException();
} else if(e.isOptional()) { } else if(e.isOptional()) {
// Optional + nil => keep default value // Optional + nil => keep default value
continue;
} else { // Nullable } else { // Nullable
// Nullable + nil => set null // Nullable + nil => set null
e.setNull(to); e.setNull(to);
continue;
} }
} else {
e.unpack(to, pac);
} }
e.unpack(to, pac);
} }
int max = length < entries.length ? length : entries.length; int max = length < entries.length ? length : entries.length;
for(; i < max; i++) { for(; i < max; i++) {
ReflectionFieldEntry e = entries[i]; ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
pac.unpackObject();
continue;
}
if(pac.tryUnpackNull()) { if(pac.tryUnpackNull()) {
// this is Optional field becaue i >= minimumArrayLength // this is Optional field becaue i >= minimumArrayLength
// Optional + nil => keep default value // Optional + nil => keep default value
continue; } else {
e.unpack(to, pac);
} }
e.unpack(to, pac);
} }
// latter entries are all Optional + nil => keep default value // latter entries are all Optional + nil => keep default value
@ -268,6 +292,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
return to; return to;
} catch (MessageTypeException e) {
throw e;
} catch (IOException e) { } catch (IOException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -290,6 +316,10 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
int i; int i;
for(i=0; i < minimumArrayLength; i++) { for(i=0; i < minimumArrayLength; i++) {
ReflectionFieldEntry e = entries[i]; ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
MessagePackObject obj = array[i]; MessagePackObject obj = array[i];
if(obj.isNil()) { if(obj.isNil()) {
if(e.isRequired()) { if(e.isRequired()) {
@ -297,32 +327,37 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
throw new MessageTypeException(); throw new MessageTypeException();
} else if(e.isOptional()) { } else if(e.isOptional()) {
// Optional + nil => keep default value // Optional + nil => keep default value
continue;
} else { // Nullable } else { // Nullable
// Nullable + nil => set null // Nullable + nil => set null
e.setNull(to); e.setNull(to);
continue;
} }
} else {
e.convert(to, obj);
} }
e.convert(to, obj);
} }
int max = length < entries.length ? length : entries.length; int max = length < entries.length ? length : entries.length;
for(; i < max; i++) { for(; i < max; i++) {
ReflectionFieldEntry e = entries[i]; ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
MessagePackObject obj = array[i]; MessagePackObject obj = array[i];
if(obj.isNil()) { if(obj.isNil()) {
// this is Optional field becaue i >= minimumArrayLength // this is Optional field becaue i >= minimumArrayLength
// Optional + nil => keep default value // Optional + nil => keep default value
continue; } else {
e.convert(to, obj);
} }
e.convert(to, obj);
} }
// latter entries are all Optional + nil => keep default value // latter entries are all Optional + nil => keep default value
return to; return to;
} catch (MessageTypeException e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
throw new MessageTypeException(e); throw new MessageTypeException(e);
} }
@ -342,7 +377,6 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
for(int i=0; i < entries.length; i++) { for(int i=0; i < entries.length; i++) {
FieldEntry e = entries[i]; FieldEntry e = entries[i];
Class<?> type = e.getType(); Class<?> type = e.getType();
System.out.println(type);
if(type.equals(boolean.class)) { if(type.equals(boolean.class)) {
res[i] = new BooleanFieldEntry(e); res[i] = new BooleanFieldEntry(e);
} else if(type.equals(byte.class)) { } else if(type.equals(byte.class)) {
@ -358,11 +392,53 @@ public class ReflectionTemplateBuilder extends TemplateBuilder {
} else if(type.equals(double.class)) { } else if(type.equals(double.class)) {
res[i] = new DoubleFieldEntry(e); res[i] = new DoubleFieldEntry(e);
} else { } else {
res[i] = new ObjectFieldEntry(e); Template tmpl = TemplateRegistry.lookup(e.getGenericType(), true);
res[i] = new ObjectFieldEntry(e, tmpl);
} }
} }
return new ReflectionTemplate(targetClass, res); return new ReflectionTemplate(targetClass, res);
} }
static class ReflectionOrdinalEnumTemplate extends AbstractTemplate {
protected Enum<?>[] entries;
protected Map<Enum<?>, Integer> reverse;
ReflectionOrdinalEnumTemplate(Enum<?>[] entries) {
this.entries = entries;
this.reverse = new HashMap<Enum<?>, Integer>();
for(int i=0; i < entries.length; i++) {
this.reverse.put(entries[i], i);
}
}
public void pack(Packer pk, Object target) throws IOException {
Integer ord = reverse.get(target);
if(ord == null) {
throw new MessageTypeException();
}
pk.pack((int)ord);
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int ord = pac.unpackInt();
if(entries.length <= ord) {
throw new MessageTypeException();
}
return entries[ord];
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
int ord = from.asInt();
if(entries.length <= ord) {
throw new MessageTypeException();
}
return entries[ord];
}
}
public Template buildOrdinalEnumTemplate(Class<?> targetClass, Enum<?>[] entries) {
return new ReflectionOrdinalEnumTemplate(entries);
}
} }

View File

@ -22,6 +22,7 @@ import java.lang.reflect.*;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet;
import org.msgpack.*; import org.msgpack.*;
import org.msgpack.annotation.*; import org.msgpack.annotation.*;
@ -50,6 +51,19 @@ public abstract class TemplateBuilder {
return field.getType(); return field.getType();
} }
public String getJavaTypeName() {
Class<?> type = field.getType();
if(type.isArray()) {
return arrayTypeToString(type);
} else {
return type.getName();
}
}
public Type getGenericType() {
return field.getGenericType();
}
public FieldOption getOption() { public FieldOption getOption() {
return option; return option;
} }
@ -73,11 +87,30 @@ public abstract class TemplateBuilder {
public boolean isAnnotated(Class<? extends Annotation> with) { public boolean isAnnotated(Class<? extends Annotation> with) {
return field.getAnnotation(with) != null; return field.getAnnotation(with) != null;
} }
static String arrayTypeToString(Class<?> type) {
int dim = 1;
Class<?> baseType = type.getComponentType();
while(baseType.isArray()) {
baseType = baseType.getComponentType();
dim += 1;
}
StringBuilder sb = new StringBuilder();
sb.append(baseType.getName());
for (int i = 0; i < dim; ++i) {
sb.append("[]");
}
return sb.toString();
}
} }
// Override this method // Override this method
public abstract Template buildTemplate(Class<?> targetClass, FieldEntry[] entries); public abstract Template buildTemplate(Class<?> targetClass, FieldEntry[] entries);
// Override this method
public abstract Template buildOrdinalEnumTemplate(Class<?> targetClass, Enum<?>[] entries);
public Template buildTemplate(Class<?> targetClass) { public Template buildTemplate(Class<?> targetClass) {
return buildTemplate(targetClass, readFieldEntries(targetClass)); return buildTemplate(targetClass, readFieldEntries(targetClass));
} }
@ -90,15 +123,22 @@ public abstract class TemplateBuilder {
return buildTemplate(targetClass, convertFieldEntries(targetClass, flist)); return buildTemplate(targetClass, convertFieldEntries(targetClass, flist));
} }
public Template buildOrdinalEnumTemplate(Class<?> targetClass) {
private static TemplateBuilder instance; Enum<?>[] entries = (Enum<?>[])targetClass.getEnumConstants();
return buildOrdinalEnumTemplate(targetClass, entries);
static {
// FIXME
instance = new ReflectionTemplateBuilder();
} }
private static TemplateBuilder instance;
static {
// FIXME
instance = JavassistTemplateBuilder.getInstance();
}
public synchronized static void setTemplateBuilder(TemplateBuilder builder) {
instance = builder;
}
public static Template build(Class<?> targetClass) { public static Template build(Class<?> targetClass) {
return instance.buildTemplate(targetClass); return instance.buildTemplate(targetClass);
} }
@ -111,6 +151,10 @@ public abstract class TemplateBuilder {
return instance.buildTemplate(targetClass, flist); return instance.buildTemplate(targetClass, flist);
} }
public static Template buildOrdinalEnum(Class<?> targetClass) {
return instance.buildOrdinalEnumTemplate(targetClass);
}
protected FieldEntry[] convertFieldEntries(Class<?> targetClass, FieldList flist) throws NoSuchFieldException { protected FieldEntry[] convertFieldEntries(Class<?> targetClass, FieldList flist) throws NoSuchFieldException {
List<FieldList.Entry> src = flist.getList(); List<FieldList.Entry> src = flist.getList();
@ -195,7 +239,7 @@ public abstract class TemplateBuilder {
Field[] result = new Field[total]; Field[] result = new Field[total];
int off = 0; int off = 0;
for(int i=succ.size()-1; i >= 0; i--) { for(int i=succ.size()-1; i >= 0; i--) {
Field[] fields = succ.get(0); Field[] fields = succ.get(i);
System.arraycopy(fields, 0, result, off, fields.length); System.arraycopy(fields, 0, result, off, fields.length);
off += fields.length; off += fields.length;
} }
@ -236,12 +280,12 @@ public abstract class TemplateBuilder {
// default mode: // default mode:
// transient : Ignore // transient : Ignore
// public : Nullable // public : Required
// others : Ignore // others : Ignore
if(Modifier.isTransient(mod)) { if(Modifier.isTransient(mod)) {
return FieldOption.IGNORE; return FieldOption.IGNORE;
} else if(Modifier.isPublic(mod)) { } else if(Modifier.isPublic(mod)) {
return FieldOption.NULLABLE; return FieldOption.REQUIRED;
} else { } else {
return FieldOption.IGNORE; return FieldOption.IGNORE;
} }