Mercurial > hg > Members > sugi > MessagePack-java
view src/main/java/org/msgpack/template/builder/AbstractTemplateBuilder.java @ 0:cb825acd883a
first commit
author | sugi |
---|---|
date | Sat, 18 Oct 2014 15:06:15 +0900 |
parents | |
children |
line wrap: on
line source
// // MessagePack for Java // // Copyright (C) 2009 - 2013 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.builder; import java.lang.annotation.Annotation; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import org.msgpack.annotation.Beans; import org.msgpack.annotation.Ignore; import org.msgpack.annotation.Index; import org.msgpack.annotation.Message; import org.msgpack.annotation.MessagePackBeans; import org.msgpack.annotation.MessagePackMessage; import org.msgpack.annotation.MessagePackOrdinalEnum; import org.msgpack.annotation.NotNullable; import org.msgpack.annotation.Optional; import org.msgpack.annotation.OrdinalEnum; import org.msgpack.template.FieldList; import org.msgpack.template.FieldOption; import org.msgpack.template.Template; import org.msgpack.template.TemplateRegistry; import org.msgpack.template.builder.TemplateBuildException; public abstract class AbstractTemplateBuilder implements TemplateBuilder { protected TemplateRegistry registry; protected AbstractTemplateBuilder(TemplateRegistry registry) { this.registry = registry; } @Override public <T> Template<T> buildTemplate(final Type targetType) throws TemplateBuildException { @SuppressWarnings("unchecked") Class<T> targetClass = (Class<T>) targetType; checkClassValidation(targetClass); FieldOption fieldOption = getFieldOption(targetClass); FieldEntry[] entries = toFieldEntries(targetClass, fieldOption); return buildTemplate(targetClass, entries); } @Override public <T> Template<T> buildTemplate(final Class<T> targetClass, final FieldList fieldList) throws TemplateBuildException { checkClassValidation(targetClass); FieldEntry[] entries = toFieldEntries(targetClass, fieldList); return buildTemplate(targetClass, entries); } protected abstract <T> Template<T> buildTemplate(Class<T> targetClass, FieldEntry[] entries); protected void checkClassValidation(final Class<?> targetClass) { if (targetClass.isInterface()) { throw new TemplateBuildException( "Cannot build template for interface: " + targetClass.getName()); } if (Modifier.isAbstract(targetClass.getModifiers())) { throw new TemplateBuildException( "Cannot build template for abstract class: " + targetClass.getName()); } if (targetClass.isArray()) { throw new TemplateBuildException( "Cannot build template for array class: " + targetClass.getName()); } if (targetClass.isPrimitive()) { throw new TemplateBuildException( "Cannot build template of primitive type: " + targetClass.getName()); } } protected FieldOption getFieldOption(Class<?> targetClass) { Message m = targetClass.getAnnotation(Message.class); if (m == null) { return FieldOption.DEFAULT; } MessagePackMessage mpm = targetClass .getAnnotation(MessagePackMessage.class); if (mpm == null) { return FieldOption.DEFAULT; } // TODO #MN return m.value(); } private FieldEntry[] toFieldEntries(final Class<?> targetClass, final FieldList flist) { List<FieldList.Entry> src = flist.getList(); FieldEntry[] entries = new FieldEntry[src.size()]; for (int i = 0; i < src.size(); i++) { FieldList.Entry s = src.get(i); if (s.isAvailable()) { try { entries[i] = new DefaultFieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption()); } catch (SecurityException e) { throw new TemplateBuildException(e); } catch (NoSuchFieldException e) { throw new TemplateBuildException(e); } } else { entries[i] = new DefaultFieldEntry(); } } return entries; } protected FieldEntry[] toFieldEntries(final Class<?> targetClass, final FieldOption from) { Field[] fields = getFields(targetClass); /* * index: * * @Index(0) * int field_a; // 0 * int field_b; // 1 * @Index(3) * int field_c; // 3 * int field_d; // 4 * @Index(2) * int field_e; // 2 * int field_f; // 5 */ List<FieldEntry> indexed = new ArrayList<FieldEntry>(); int maxIndex = -1; for (Field f : fields) { FieldOption opt = getFieldOption(f, from); if (opt == FieldOption.IGNORE) { // skip continue; } int index = getFieldIndex(f, maxIndex); if (indexed.size() > index && indexed.get(index) != null) { throw new TemplateBuildException("duplicated index: " + index); } if (index < 0) { throw new TemplateBuildException("invalid index: " + index); } while (indexed.size() <= index) { indexed.add(null); } indexed.set(index, new DefaultFieldEntry(f, opt)); if (maxIndex < index) { maxIndex = index; } } FieldEntry[] entries = new FieldEntry[maxIndex + 1]; for (int i = 0; i < indexed.size(); i++) { FieldEntry e = indexed.get(i); if (e == null) { entries[i] = new DefaultFieldEntry(); } else { entries[i] = e; } } return entries; } private Field[] getFields(Class<?> targetClass) { // order: [fields of super class, ..., fields of this class] List<Field[]> succ = new ArrayList<Field[]>(); int total = 0; for (Class<?> c = targetClass; c != Object.class; c = c.getSuperclass()) { Field[] fields = c.getDeclaredFields(); total += fields.length; succ.add(fields); } Field[] result = new Field[total]; int off = 0; for (int i = succ.size() - 1; i >= 0; i--) { Field[] fields = succ.get(i); System.arraycopy(fields, 0, result, off, fields.length); off += fields.length; } return result; } private FieldOption getFieldOption(Field field, FieldOption from) { int mod = field.getModifiers(); // default mode: // transient, static, final : Ignore // primitive type : NotNullable // reference type : Ignore if (Modifier.isStatic(mod) || Modifier.isFinal(mod) || Modifier.isTransient(mod)) { return FieldOption.IGNORE; } if (isAnnotated(field, Ignore.class)) { return FieldOption.IGNORE; } else if (isAnnotated(field, Optional.class)) { return FieldOption.OPTIONAL; } else if (isAnnotated(field, NotNullable.class)) { return FieldOption.NOTNULLABLE; } if (from != FieldOption.DEFAULT) { return from; } if (field.getType().isPrimitive()) { return FieldOption.NOTNULLABLE; } else { return FieldOption.OPTIONAL; } } private int getFieldIndex(final Field field, int maxIndex) { Index a = field.getAnnotation(Index.class); if (a == null) { return maxIndex + 1; } else { return a.value(); } } @Override public void writeTemplate(Type targetType, String directoryName) { throw new UnsupportedOperationException(targetType.toString()); } @Override public <T> Template<T> loadTemplate(Type targetType) { return null; } public static boolean isAnnotated(Class<?> targetClass, Class<? extends Annotation> with) { return targetClass.getAnnotation(with) != null; } public static boolean isAnnotated(AccessibleObject accessibleObject, Class<? extends Annotation> with) { return accessibleObject.getAnnotation(with) != null; } public static boolean matchAtClassTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { if (hasAnnotation) { return AbstractTemplateBuilder.isAnnotated(targetClass, Message.class) || AbstractTemplateBuilder.isAnnotated(targetClass, MessagePackMessage.class); } else { return !targetClass.isEnum() && !targetClass.isInterface(); } } public static boolean matchAtBeansClassTemplateBuilder(Type targetType, boolean hasAnnotation) { Class<?> targetClass = (Class<?>) targetType; if (hasAnnotation) { return AbstractTemplateBuilder.isAnnotated((Class<?>) targetType, Beans.class) || AbstractTemplateBuilder.isAnnotated((Class<?>) targetType, MessagePackBeans.class); } else { return !targetClass.isEnum() || !targetClass.isInterface(); } } public static boolean matchAtArrayTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { if (((Type) targetClass) instanceof GenericArrayType) { return true; } return targetClass.isArray(); } public static boolean matchAtOrdinalEnumTemplateBuilder(Class<?> targetClass, boolean hasAnnotation) { if (hasAnnotation) { return AbstractTemplateBuilder.isAnnotated(targetClass, OrdinalEnum.class) || AbstractTemplateBuilder.isAnnotated(targetClass, MessagePackOrdinalEnum.class); } else { return targetClass.isEnum(); } } }