package phantomlancer.tools; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.avro.AvroTypeException; import org.apache.avro.Schema; import org.apache.avro.Schema.Field; import org.apache.avro.Schema.Type; import org.apache.commons.lang3.Validate; import org.codehaus.jackson.node.NullNode; import phantomlancer.AvscSchemaBuilder; import phantomlancer.annotation.AvroScan; import com.google.common.collect.Maps; public class JavaClass2Type { private static final Map<Class<?>, Type> JAVACLASS2TYPE = Maps.newHashMap(); static { JAVACLASS2TYPE.put(Boolean.class, Type.BOOLEAN); JAVACLASS2TYPE.put(boolean.class, Type.BOOLEAN); JAVACLASS2TYPE.put(Byte.class, Type.BYTES); JAVACLASS2TYPE.put(Byte.TYPE, Type.BYTES); JAVACLASS2TYPE.put(Short.class, Type.INT); JAVACLASS2TYPE.put(Short.TYPE, Type.INT); JAVACLASS2TYPE.put(Integer.class, Type.INT); JAVACLASS2TYPE.put(Integer.TYPE, Type.INT); JAVACLASS2TYPE.put(Long.class, Type.LONG); JAVACLASS2TYPE.put(Long.TYPE, Type.LONG); JAVACLASS2TYPE.put(Float.class, Type.FLOAT); JAVACLASS2TYPE.put(Float.TYPE, Type.FLOAT); JAVACLASS2TYPE.put(Double.class, Type.DOUBLE); JAVACLASS2TYPE.put(Double.TYPE, Type.DOUBLE); JAVACLASS2TYPE.put(String.class, Type.STRING); JAVACLASS2TYPE.put(Character.class, Type.STRING); JAVACLASS2TYPE.put(Character.TYPE, Type.STRING); JAVACLASS2TYPE.put(java.util.Date.class, Type.STRING); JAVACLASS2TYPE.put(java.sql.Date.class, Type.STRING); JAVACLASS2TYPE.put(java.sql.Time.class, Type.STRING); JAVACLASS2TYPE.put(java.sql.Timestamp.class, Type.STRING); JAVACLASS2TYPE.put(Void.class, Type.NULL); JAVACLASS2TYPE.put(Void.TYPE, Type.NULL); } private static Schema toAvroSchema(Class<?> c, boolean allCanBeNull) { Type p = JAVACLASS2TYPE.get(c); Validate.isTrue(p != null, "Java Class Type Not Found : %s", c); if (allCanBeNull) { List<Schema> childSchemas = new ArrayList<Schema>(); childSchemas.add(Schema.create(Schema.Type.NULL)); childSchemas.add(Schema.create(p)); return Schema.createUnion(childSchemas); } else { return Schema.create(p); } } public static Field toAvroField(java.lang.reflect.Field field, AvroScan avroScan) { java.lang.reflect.Type type = field.getGenericType(); Class<?> fieldClass = field.getType(); String fieldName = field.getName(); return toAvroField(type, fieldClass, fieldName, avroScan); } public static Field toAvroField(java.lang.reflect.Type genericType, Class<?> fieldClass, String fieldName, AvroScan avroScan) { Field avscField = null; if (JAVACLASS2TYPE.containsKey(fieldClass)) { Schema avroSchema = toAvroSchema(fieldClass, avroScan.allCanBeNull()); avscField = new Field(fieldName, avroSchema, null, avroScan.allCanBeNull() ? NullNode.getInstance() : null); } else if (fieldClass.isArray() || Collection.class.isAssignableFrom(fieldClass)) { Field item = null; if (fieldClass.isArray()) { item = toAvroField(fieldClass.getComponentType(), fieldClass.getComponentType(), fieldName, avroScan); } if (Collection.class.isAssignableFrom(fieldClass)) { ParameterizedType ptype = (ParameterizedType) genericType; java.lang.reflect.Type[] params = ptype.getActualTypeArguments(); Class<?> nextC = (params[0] instanceof ParameterizedType ? (Class<?>) ((ParameterizedType) params[0]).getRawType() : (Class<?>) params[0]); item = toAvroField(params[0], nextC, fieldName, avroScan); } if (item != null) { Schema arraySchema = Schema.createArray(item.schema()); avscField = new Field(fieldName, arraySchema, null, null); } } else if (Map.class.isAssignableFrom(fieldClass)) { ParameterizedType ptype = (ParameterizedType) genericType; java.lang.reflect.Type[] params = ptype.getActualTypeArguments(); java.lang.reflect.Type key = params[0]; java.lang.reflect.Type value = params[1]; if (!(key instanceof Class && CharSequence.class.isAssignableFrom((Class<?>) key))) { throw new AvroTypeException("Map key class not CharSequence: " + key); } Class<?> nextC = (value instanceof ParameterizedType ? (Class<?>) ((ParameterizedType) value).getRawType() : (Class<?>) value); Field item = toAvroField(value, nextC, fieldName, avroScan); if (item != null) { Schema arraySchema = Schema.createMap(item.schema()); avscField = new Field(fieldName, arraySchema, null, null); } } else if (fieldClass.getAnnotation(AvroScan.class) != null) { AvscSchemaBuilder asb = new AvscSchemaBuilder(fieldClass); Schema avroSchema = asb.createSchema(); avscField = new Field(fieldName, avroSchema, null, null); } return avscField; } }