Package org.msgpack.template.builder

Source Code of org.msgpack.template.builder.AbstractTemplateBuilder

//
// 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.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.Ignore;
import org.msgpack.annotation.Index;
import org.msgpack.annotation.Message;
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 (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 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();
  }
    }
}
TOP

Related Classes of org.msgpack.template.builder.AbstractTemplateBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.