diff --git a/java/msgpack.iml b/java/msgpack.iml
new file mode 100644
index 00000000..3a6d962d
--- /dev/null
+++ b/java/msgpack.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/pom.xml b/java/pom.xml
index c8a19b3a..39149d20 100755
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -81,6 +81,20 @@
scm:git://github.com/msgpack/msgpack.git
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
@@ -132,12 +146,14 @@
msgpack.org
Repository at msgpack.org
file://${project.build.directory}/website/maven2/
+
true
msgpack.org
Repository at msgpack.org
file://${project.build.directory}/website/maven2/
+
diff --git a/java/src/main/java/org/msgpack/MessagePack.java b/java/src/main/java/org/msgpack/MessagePack.java
index 4bb5d2ca..a650b797 100644
--- a/java/src/main/java/org/msgpack/MessagePack.java
+++ b/java/src/main/java/org/msgpack/MessagePack.java
@@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.msgpack.template.TemplateRegistry;
-import org.msgpack.template.TemplateBuilder;
import org.msgpack.template.TemplateClassWriter;
import org.msgpack.template.FieldList;
diff --git a/java/src/main/java/org/msgpack/annotation/Ignore.java b/java/src/main/java/org/msgpack/annotation/Ignore.java
index 96a37bb6..e052e58a 100644
--- a/java/src/main/java/org/msgpack/annotation/Ignore.java
+++ b/java/src/main/java/org/msgpack/annotation/Ignore.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Ignore {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Index.java b/java/src/main/java/org/msgpack/annotation/Index.java
index 7c1b6598..d3b2181f 100644
--- a/java/src/main/java/org/msgpack/annotation/Index.java
+++ b/java/src/main/java/org/msgpack/annotation/Index.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
int value();
diff --git a/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java b/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java
new file mode 100644
index 00000000..bff1b0d2
--- /dev/null
+++ b/java/src/main/java/org/msgpack/annotation/MessagePackBeans.java
@@ -0,0 +1,35 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package org.msgpack.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.msgpack.template.FieldOption;
+
+/**
+ * Annotation for java beans class
+ * @author takeshita
+ *
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MessagePackBeans {
+ FieldOption value() default FieldOption.DEFAULT;
+}
diff --git a/java/src/main/java/org/msgpack/annotation/Nullable.java b/java/src/main/java/org/msgpack/annotation/Nullable.java
index e6893e72..56aea89e 100644
--- a/java/src/main/java/org/msgpack/annotation/Nullable.java
+++ b/java/src/main/java/org/msgpack/annotation/Nullable.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Optional.java b/java/src/main/java/org/msgpack/annotation/Optional.java
index 7894f881..a137ec86 100644
--- a/java/src/main/java/org/msgpack/annotation/Optional.java
+++ b/java/src/main/java/org/msgpack/annotation/Optional.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Optional {
}
diff --git a/java/src/main/java/org/msgpack/annotation/Required.java b/java/src/main/java/org/msgpack/annotation/Required.java
index 16311085..de1d816b 100644
--- a/java/src/main/java/org/msgpack/annotation/Required.java
+++ b/java/src/main/java/org/msgpack/annotation/Required.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {
}
diff --git a/java/src/main/java/org/msgpack/template/BeansFieldEntry.java b/java/src/main/java/org/msgpack/template/BeansFieldEntry.java
new file mode 100644
index 00000000..5d5ff816
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BeansFieldEntry.java
@@ -0,0 +1,143 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package org.msgpack.template;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.*;
+import org.msgpack.*;
+
+/**
+ * Field entry for Java beans property.
+ * @author takeshita
+ *
+ */
+public class BeansFieldEntry implements IFieldEntry {
+
+ PropertyDescriptor desc;
+ FieldOption option = FieldOption.DEFAULT;
+
+ public BeansFieldEntry(PropertyDescriptor desc) {
+ this.desc = desc;
+ }
+
+ @Override
+ public String getName() {
+ return desc.getDisplayName();
+ }
+ public String getGetterName(){
+ return desc.getReadMethod().getName();
+ }
+ public String getSetterName(){
+ return desc.getWriteMethod().getName();
+ }
+
+ @Override
+ public Class> getType() {
+ return desc.getPropertyType();
+ }
+
+ @Override
+ public String getJavaTypeName() {
+ Class> type = getType();
+ if(type.isArray()) {
+ return arrayTypeToString(type);
+ } else {
+ return type.getName();
+ }
+ }
+ 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
+ public Type getGenericType() {
+ return desc.getReadMethod().getGenericReturnType();
+ }
+
+ @Override
+ public FieldOption getOption() {
+ return option;
+ }
+ public void setOption(FieldOption option){
+ this.option = option;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return option != FieldOption.IGNORE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isRequired()
+ */
+ @Override
+ public boolean isRequired() {
+ return option == FieldOption.REQUIRED;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isOptional()
+ */
+ @Override
+ public boolean isOptional() {
+ return option == FieldOption.OPTIONAL;
+ }
+
+ /* (non-Javadoc)
+ * @see org.msgpack.template.IFieldEntry#isNullable()
+ */
+ @Override
+ public boolean isNullable() {
+ return option == FieldOption.NULLABLE;
+ }
+
+ public Object get(Object target){
+ try {
+ return desc.getReadMethod().invoke(target);
+ } catch (IllegalArgumentException e) {
+ throw new MessageTypeException(e);
+ } catch (IllegalAccessException e) {
+ throw new MessageTypeException(e);
+ } catch (InvocationTargetException e) {
+ throw new MessageTypeException(e);
+ }
+ }
+ public void set(Object target , Object value){
+ try {
+ desc.getWriteMethod().invoke(target, value);
+ } catch (IllegalArgumentException e) {
+ throw new MessageTypeException(e);
+ } catch (IllegalAccessException e) {
+ throw new MessageTypeException(e);
+ } catch (InvocationTargetException e) {
+ throw new MessageTypeException(e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java b/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java
new file mode 100644
index 00000000..9d3039b2
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BeansFieldEntryReader.java
@@ -0,0 +1,188 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package org.msgpack.template;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.msgpack.annotation.Ignore;
+import org.msgpack.annotation.Index;
+import org.msgpack.annotation.MessagePackMessage;
+import org.msgpack.annotation.Nullable;
+import org.msgpack.annotation.Optional;
+import org.msgpack.annotation.Required;
+
+/**
+ * List up Java beans property methods.
+ * @author takeshita
+ *
+ */
+public class BeansFieldEntryReader implements IFieldEntryReader{
+
+
+ public IFieldEntry[] convertFieldEntries(Class> targetClass, FieldList flist) throws NoSuchFieldException {
+ List src = flist.getList();
+ FieldEntry[] result = new FieldEntry[src.size()];
+ for(int i=0; i < src.size(); i++) {
+ FieldList.Entry s = src.get(i);
+ if(s.isAvailable()) {
+ result[i] = new FieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption());
+ } else {
+ result[i] = new FieldEntry();
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public IFieldEntry[] readFieldEntries(Class> targetClass,
+ FieldOption implicitOption) {
+ BeanInfo desc;
+ try {
+ desc = Introspector.getBeanInfo(targetClass);
+ } catch (IntrospectionException e1) {
+ throw new TemplateBuildException("Class must be java beans class:" + targetClass.getName());
+ }
+
+ PropertyDescriptor[] props = desc.getPropertyDescriptors();
+ ArrayList list = new ArrayList();
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor pd = props[i];
+ if(!isIgnoreProp(pd)){
+ list.add(pd);
+ }
+ }
+ props = new PropertyDescriptor[list.size()];
+ list.toArray(props);
+
+ BeansFieldEntry[] entries = new BeansFieldEntry[props.length];
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor p = props[i];
+ int index = readPropIndex(p);
+ if(index >= 0){
+ if(entries[index] != null){
+ throw new TemplateBuildException("duplicated index: "+index);
+ }
+ if(index >= entries.length){
+ throw new TemplateBuildException("invalid index: "+index);
+ }
+ entries[index] = new BeansFieldEntry(p);
+ props[index] = null;
+ }
+ }
+ int insertIndex = 0;
+ for(int i = 0;i < props.length;i++){
+ PropertyDescriptor p = props[i];
+ if(p != null){
+ while(entries[insertIndex] != null){
+ insertIndex++;
+ }
+ entries[insertIndex] = new BeansFieldEntry(p);
+ }
+
+ }
+ for(int i = 0;i < entries.length;i++){
+ BeansFieldEntry e = entries[i];
+ FieldOption op = readPropOption(e.desc, implicitOption);
+ e.setOption(op);
+ }
+ return entries;
+ }
+
+ public FieldOption readImplicitFieldOption(Class> targetClass) {
+ MessagePackMessage a = targetClass.getAnnotation(MessagePackMessage.class);
+ if(a == null) {
+ return FieldOption.DEFAULT;
+ }
+ return a.value();
+ }
+
+
+ private FieldOption readPropOption(PropertyDescriptor desc, FieldOption implicitOption) {
+
+ FieldOption forGetter = readMethodOption(desc.getReadMethod());
+ if(forGetter != FieldOption.DEFAULT){
+ return forGetter;
+ }
+ FieldOption forSetter = readMethodOption(desc.getWriteMethod());
+ if(forSetter != FieldOption.DEFAULT){
+ return forSetter;
+ }else{
+ return implicitOption;
+ }
+
+ }
+ private FieldOption readMethodOption(Method method){
+
+ if(isAnnotated(method, Ignore.class)) {
+ return FieldOption.IGNORE;
+ } else if(isAnnotated(method, Required.class)) {
+ return FieldOption.REQUIRED;
+ } else if(isAnnotated(method, Optional.class)) {
+ return FieldOption.OPTIONAL;
+ } else if(isAnnotated(method, Nullable.class)) {
+ if(method.getDeclaringClass().isPrimitive()) {
+ return FieldOption.REQUIRED;
+ } else {
+ return FieldOption.NULLABLE;
+ }
+ }
+ return FieldOption.DEFAULT;
+ }
+
+ private int readPropIndex(PropertyDescriptor desc) {
+
+ int forGetter = readMethodIndex(desc.getReadMethod());
+ if(forGetter >= 0){
+ return forGetter;
+ }
+ int forSetter = readMethodIndex(desc.getWriteMethod());
+ return forSetter;
+ }
+ private int readMethodIndex(Method method){
+ Index a = method.getAnnotation(Index.class);
+ if(a == null) {
+ return -1;
+ } else {
+ return a.value();
+ }
+ }
+
+ private boolean isAnnotated(AccessibleObject ao, Class extends Annotation> with) {
+ return ao.getAnnotation(with) != null;
+ }
+ boolean isIgnoreProp(PropertyDescriptor desc){
+ if(desc == null)return true;
+ Method getter = desc.getReadMethod();
+ Method setter = desc.getWriteMethod();
+ return getter == null ||
+ setter == null ||
+ !Modifier.isPublic(getter.getModifiers()) ||
+ !Modifier.isPublic(setter.getModifiers()) ||
+ isAnnotated(getter,Ignore.class) ||
+ isAnnotated(setter, Ignore.class);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/template/BeansReflectionTemplateBuilder.java b/java/src/main/java/org/msgpack/template/BeansReflectionTemplateBuilder.java
new file mode 100644
index 00000000..e97531f7
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/BeansReflectionTemplateBuilder.java
@@ -0,0 +1,338 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2011 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package org.msgpack.template;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+import org.msgpack.AbstractTemplate;
+import org.msgpack.MessagePackObject;
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Template;
+import org.msgpack.Unpacker;
+import org.msgpack.template.ReflectionTemplateBuilder.BooleanFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.ByteFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.DoubleFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.FloatFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.IntFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.LongFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.NullFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.ObjectFieldEntry;
+import org.msgpack.template.ReflectionTemplateBuilder.ShortFieldEntry;
+import org.msgpack.template.builder.CustomTemplateBuilder;
+
+/**
+ * Class for building java reflection template builder for java beans class.
+ * @author takeshita
+ *
+ */
+public class BeansReflectionTemplateBuilder extends CustomTemplateBuilder{
+
+ IFieldEntryReader reader = new BeansFieldEntryReader();
+
+ public BeansReflectionTemplateBuilder(){}
+
+ @Override
+ public IFieldEntryReader getFieldEntryReader(){
+ return reader;
+ }
+
+ static class ReflectionEntry{
+ BeansFieldEntry entry;
+ public ReflectionEntry(BeansFieldEntry entry){
+ this.entry = entry;
+ }
+
+ public void pack(Object value , Packer packer) throws IOException{
+ packer.pack(value);
+ }
+ public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
+ entry.set(target, obj.convert(entry.getType()));
+ }
+
+ public void unpack(Object target, Unpacker unpacker) throws IOException, MessageTypeException, IllegalAccessException {
+ entry.set(target, unpacker.unpack(entry.getType()));
+ }
+
+ public void setNull(Object target){
+ entry.set(target, null);
+ }
+
+ public boolean isRequired(){
+ return entry.isRequired();
+ }
+ public boolean isNullable(){
+ return entry.isNullable();
+ }
+ public boolean isAvailable(){
+ return entry.isAvailable();
+ }
+ public boolean isOptional(){
+ return entry.isOptional();
+ }
+ public Object get(Object target){
+ return entry.get(target);
+ }
+
+ }
+
+ static class ObjectFieldEntry extends ReflectionEntry{
+ Template template;
+ public ObjectFieldEntry(BeansFieldEntry entry,Template template){
+ super(entry);
+ this.template = template;
+ }
+ public void pack(Object value , Packer packer) throws IOException{
+ template.pack(packer,value);
+ }
+ public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
+ Class