From 0339db57f19ca6418732f251bfebf95d86b67c38 Mon Sep 17 00:00:00 2001 From: FURUHASHI Sadayuki Date: Wed, 1 Dec 2010 20:38:58 +0900 Subject: [PATCH] java: adds TemplateBuilder and ReflectionTemplateBUilder --- .../template/ReflectionTemplateBuilder.java | 164 +++++++++++++----- .../org/msgpack/template/TemplateBuilder.java | 62 ++++++- 2 files changed, 173 insertions(+), 53 deletions(-) diff --git a/java/src/main/java/org/msgpack/template/ReflectionTemplateBuilder.java b/java/src/main/java/org/msgpack/template/ReflectionTemplateBuilder.java index 05b8b80a..aecde46e 100644 --- a/java/src/main/java/org/msgpack/template/ReflectionTemplateBuilder.java +++ b/java/src/main/java/org/msgpack/template/ReflectionTemplateBuilder.java @@ -19,13 +19,23 @@ package org.msgpack.template; import java.io.IOException; import java.lang.reflect.*; +import java.util.Map; +import java.util.HashMap; import org.msgpack.*; 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) { super(e.getField(), e.getOption()); } @@ -41,41 +51,41 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class ObjectFieldEntry extends ReflectionFieldEntry { - public ObjectFieldEntry(FieldEntry e) { + static class ObjectFieldEntry extends ReflectionFieldEntry { + private Template template; + + ObjectFieldEntry(FieldEntry e, Template template) { super(e); + this.template = template; } public void pack(Object target, Packer pac) throws IOException { - // TODO: call template - pac.pack(target); + template.pack(pac, target); } public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException { - // TODO: call template Field f = getField(); Class type = (Class)f.getType(); Object fieldReference = f.get(target); - Object valueReference = obj.convert(type, fieldReference); + Object valueReference = template.convert(obj, fieldReference); if(valueReference != fieldReference) { f.set(target, valueReference); } } public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException { - // TODO: call template Field f = getField(); Class type = (Class)f.getType(); Object fieldReference = f.get(target); - Object valueReference = pac.unpack(type, fieldReference); + Object valueReference = template.unpack(pac, fieldReference); if(valueReference != fieldReference) { f.set(target, valueReference); } } } - public static class BooleanFieldEntry extends ReflectionFieldEntry { - public BooleanFieldEntry(FieldEntry e) { + static class BooleanFieldEntry extends ReflectionFieldEntry { + BooleanFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -89,8 +99,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class ByteFieldEntry extends ReflectionFieldEntry { - public ByteFieldEntry(FieldEntry e) { + static class ByteFieldEntry extends ReflectionFieldEntry { + ByteFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -104,8 +114,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class ShortFieldEntry extends ReflectionFieldEntry { - public ShortFieldEntry(FieldEntry e) { + static class ShortFieldEntry extends ReflectionFieldEntry { + ShortFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -119,8 +129,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class IntFieldEntry extends ReflectionFieldEntry { - public IntFieldEntry(FieldEntry e) { + static class IntFieldEntry extends ReflectionFieldEntry { + IntFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -134,8 +144,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class LongFieldEntry extends ReflectionFieldEntry { - public LongFieldEntry(FieldEntry e) { + static class LongFieldEntry extends ReflectionFieldEntry { + LongFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -149,8 +159,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class FloatFieldEntry extends ReflectionFieldEntry { - public FloatFieldEntry(FieldEntry e) { + static class FloatFieldEntry extends ReflectionFieldEntry { + FloatFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -164,8 +174,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - public static class DoubleFieldEntry extends ReflectionFieldEntry { - public DoubleFieldEntry(FieldEntry e) { + static class DoubleFieldEntry extends ReflectionFieldEntry { + DoubleFieldEntry(FieldEntry e) { super(e); } public void pack(Object target, Packer pac) throws IOException { @@ -179,17 +189,19 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } } - private static class ReflectionTemplate extends AbstractTemplate { - private Class targetClass; - private ReflectionFieldEntry[] entries; - private int minimumArrayLength; + static class ReflectionTemplate extends AbstractTemplate { + protected Class targetClass; + protected ReflectionFieldEntry[] entries; + protected int minimumArrayLength; - public ReflectionTemplate(Class targetClass, ReflectionFieldEntry[] entries) { + ReflectionTemplate(Class targetClass, ReflectionFieldEntry[] entries) { this.targetClass = targetClass; this.entries = entries; + this.minimumArrayLength = 0; for(int i=0; i < entries.length; i++) { - if(entries[i].isRequired() || entries[i].isNullable()) { - minimumArrayLength = i+1; + ReflectionFieldEntry e = entries[i]; + if(e.isRequired() || e.isNullable()) { + this.minimumArrayLength = i+1; } } } @@ -209,9 +221,12 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } pk.packNil(); } else { - pk.pack(obj); // TODO: call template + e.pack(obj, pk); } } + + } catch (MessageTypeException e) { + throw e; } catch (IOException e) { throw e; } catch (Exception e) { @@ -233,31 +248,40 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { int i; for(i=0; i < minimumArrayLength; i++) { ReflectionFieldEntry e = entries[i]; + if(!e.isAvailable()) { + pac.unpackObject(); + continue; + } + if(pac.tryUnpackNull()) { if(e.isRequired()) { // Requred + nil => exception throw new MessageTypeException(); } else if(e.isOptional()) { // Optional + nil => keep default value - continue; } else { // Nullable // Nullable + nil => set null e.setNull(to); - continue; } + } else { + e.unpack(to, pac); } - e.unpack(to, pac); } int max = length < entries.length ? length : entries.length; for(; i < max; i++) { ReflectionFieldEntry e = entries[i]; + if(!e.isAvailable()) { + pac.unpackObject(); + continue; + } + if(pac.tryUnpackNull()) { // this is Optional field becaue i >= minimumArrayLength // Optional + nil => keep default value - continue; + } else { + e.unpack(to, pac); } - e.unpack(to, pac); } // latter entries are all Optional + nil => keep default value @@ -268,6 +292,8 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { return to; + } catch (MessageTypeException e) { + throw e; } catch (IOException e) { throw e; } catch (Exception e) { @@ -290,6 +316,10 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { int i; for(i=0; i < minimumArrayLength; i++) { ReflectionFieldEntry e = entries[i]; + if(!e.isAvailable()) { + continue; + } + MessagePackObject obj = array[i]; if(obj.isNil()) { if(e.isRequired()) { @@ -297,32 +327,37 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { throw new MessageTypeException(); } else if(e.isOptional()) { // Optional + nil => keep default value - continue; } else { // Nullable // Nullable + nil => set null e.setNull(to); - continue; } + } else { + e.convert(to, obj); } - e.convert(to, obj); } int max = length < entries.length ? length : entries.length; for(; i < max; i++) { ReflectionFieldEntry e = entries[i]; + if(!e.isAvailable()) { + continue; + } + MessagePackObject obj = array[i]; if(obj.isNil()) { // this is Optional field becaue i >= minimumArrayLength // Optional + nil => keep default value - continue; + } else { + e.convert(to, obj); } - e.convert(to, obj); } // latter entries are all Optional + nil => keep default value return to; + } catch (MessageTypeException e) { + throw e; } catch (Exception e) { throw new MessageTypeException(e); } @@ -342,7 +377,6 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { for(int i=0; i < entries.length; i++) { FieldEntry e = entries[i]; Class type = e.getType(); - System.out.println(type); if(type.equals(boolean.class)) { res[i] = new BooleanFieldEntry(e); } else if(type.equals(byte.class)) { @@ -358,11 +392,53 @@ public class ReflectionTemplateBuilder extends TemplateBuilder { } else if(type.equals(double.class)) { res[i] = new DoubleFieldEntry(e); } else { - res[i] = new ObjectFieldEntry(e); + Template tmpl = TemplateRegistry.lookup(e.getGenericType(), true); + res[i] = new ObjectFieldEntry(e, tmpl); } } return new ReflectionTemplate(targetClass, res); } + + static class ReflectionOrdinalEnumTemplate extends AbstractTemplate { + protected Enum[] entries; + protected Map, Integer> reverse; + + ReflectionOrdinalEnumTemplate(Enum[] entries) { + this.entries = entries; + this.reverse = new HashMap, 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); + } } diff --git a/java/src/main/java/org/msgpack/template/TemplateBuilder.java b/java/src/main/java/org/msgpack/template/TemplateBuilder.java index 93898650..47942678 100644 --- a/java/src/main/java/org/msgpack/template/TemplateBuilder.java +++ b/java/src/main/java/org/msgpack/template/TemplateBuilder.java @@ -22,6 +22,7 @@ import java.lang.reflect.*; import java.lang.annotation.*; import java.util.List; import java.util.ArrayList; +import java.util.EnumSet; import org.msgpack.*; import org.msgpack.annotation.*; @@ -50,6 +51,19 @@ public abstract class TemplateBuilder { 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() { return option; } @@ -73,11 +87,30 @@ public abstract class TemplateBuilder { public boolean isAnnotated(Class with) { 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 public abstract Template buildTemplate(Class targetClass, FieldEntry[] entries); + // Override this method + public abstract Template buildOrdinalEnumTemplate(Class targetClass, Enum[] entries); + + public Template buildTemplate(Class targetClass) { return buildTemplate(targetClass, readFieldEntries(targetClass)); } @@ -90,15 +123,22 @@ public abstract class TemplateBuilder { return buildTemplate(targetClass, convertFieldEntries(targetClass, flist)); } - - private static TemplateBuilder instance; - - static { - // FIXME - instance = new ReflectionTemplateBuilder(); + public Template buildOrdinalEnumTemplate(Class targetClass) { + Enum[] entries = (Enum[])targetClass.getEnumConstants(); + return buildOrdinalEnumTemplate(targetClass, entries); } + private static TemplateBuilder instance; + static { + // FIXME + instance = JavassistTemplateBuilder.getInstance(); + } + + public synchronized static void setTemplateBuilder(TemplateBuilder builder) { + instance = builder; + } + public static Template build(Class targetClass) { return instance.buildTemplate(targetClass); } @@ -111,6 +151,10 @@ public abstract class TemplateBuilder { return instance.buildTemplate(targetClass, flist); } + public static Template buildOrdinalEnum(Class targetClass) { + return instance.buildOrdinalEnumTemplate(targetClass); + } + protected FieldEntry[] convertFieldEntries(Class targetClass, FieldList flist) throws NoSuchFieldException { List src = flist.getList(); @@ -195,7 +239,7 @@ public abstract class TemplateBuilder { Field[] result = new Field[total]; int off = 0; 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); off += fields.length; } @@ -236,12 +280,12 @@ public abstract class TemplateBuilder { // default mode: // transient : Ignore - // public : Nullable + // public : Required // others : Ignore if(Modifier.isTransient(mod)) { return FieldOption.IGNORE; } else if(Modifier.isPublic(mod)) { - return FieldOption.NULLABLE; + return FieldOption.REQUIRED; } else { return FieldOption.IGNORE; }