/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.pojo.codebase;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.whole.lang.builders.IBuilderOperation;
import org.whole.lang.pojo.builders.IPojoBuilder;
import org.whole.lang.pojo.model.CollectionInterfaceEnum;
import org.whole.lang.pojo.model.ModifierEnum;
import org.whole.lang.pojo.reflect.PojoLanguageKit;
import org.whole.lang.templates.AbstractTemplateFactory;
import org.whole.lang.util.StringUtils;
public class PojoRevEngTemplateFactory extends AbstractTemplateFactory {
private String modelName;
private String packageName;
private Class<?>[] classes;
private String excludedInterfaces;
public PojoRevEngTemplateFactory(String modelName, String packageName, Class<?>[] classes, String excludedInterfaces) {
this.modelName = modelName;
this.packageName = packageName;
this.classes = classes;
this.excludedInterfaces = excludedInterfaces;
}
protected boolean includesInterface(String name) {
return !StringUtils.inList(name, excludedInterfaces);
}
protected boolean hasSamePackage(Class<?> clazz) {
Package pkg = clazz.getPackage();
return pkg != null ? pkg.getName().equals(packageName) : false;
}
public void apply(IBuilderOperation op) {
buildPojoModel((IPojoBuilder) op.wGetBuilder(PojoLanguageKit.URI));
}
private void buildPojoModel(IPojoBuilder builder) {
builder.Library_();
builder.Annotations();
builder.Name(modelName);
builder.Declarations_(classes.length);
for(Class<?> clazz: classes)
buildPojoDeclaration(clazz, builder);
builder._Declarations();
builder._Library();
}
private void buildPojoDeclaration(Class<?> clazz, IPojoBuilder builder) {
builder.PojoDeclaration_();
{
builder.Annotations();
builder.Name(clazz.getSimpleName());
Class<?>[] interfaces = clazz.getInterfaces();
builder.Names_(interfaces.length);
for (int i = 0; i < interfaces.length; i++) {
if (hasSamePackage(interfaces[i])) {
String interfaceName = interfaces[i].getSimpleName();
if (includesInterface(interfaceName))
builder.Name(interfaceName);
}
}
builder._Names();
buildProperties(clazz, builder);
}
builder._PojoDeclaration();
}
private void buildProperties(Class<?> clazz, IPojoBuilder builder) {
builder.Properties_();
{
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
builder.Property_();
builder.Annotations();
Type genericFieldType = field.getGenericType();
buildProperty(genericFieldType, builder);
builder.Name(field.getName());
builder._Property();
}
}
builder._Properties();
}
private static final boolean isAssignableParametrizedType(Class<?> assignTo, ParameterizedType ptype) {
if(ptype == null)
return false;
Type rawType = ptype.getRawType();
return assignTo.isAssignableFrom((Class<?>)rawType);
}
private void buildProperty(Type genericFieldType, IPojoBuilder builder) {
if (genericFieldType instanceof ParameterizedType &&
isAssignableParametrizedType(Collection.class, (ParameterizedType)genericFieldType))
buildCollectionProperty(genericFieldType, builder);
else if (genericFieldType instanceof ParameterizedType &&
isAssignableParametrizedType(Map.class, (ParameterizedType)genericFieldType))
buildMapProperty(genericFieldType, builder);
else if(genericFieldType instanceof GenericArrayType)
buildArrayProperty(genericFieldType, builder);
else if (genericFieldType instanceof Class<?>) {
if (((Class<?>)genericFieldType).isPrimitive() ||
// myClazz.equals(EnumValue.class) ||
// myClazz.equals(Date.class) ||
genericFieldType.equals(String.class)) {
buildPrimitiveProperty((Class<?>)genericFieldType, builder);
} else if (((Class<?>)genericFieldType).isArray()) {
buildArrayProperty(genericFieldType, builder);
} else if (Collection.class.isAssignableFrom((Class<?>)genericFieldType)) {
buildCollectionProperty(genericFieldType, builder);
} else if (Map.class.isAssignableFrom((Class<?>)genericFieldType)) {
buildMapProperty(genericFieldType, builder);
} else if (hasSamePackage((Class<?>)genericFieldType)) {
builder.ReferenceType(((Class<?>)genericFieldType).getSimpleName());
} else {
buildReferenceProperty((Class<?>)genericFieldType, builder);
}
} else
throw new IllegalArgumentException("Usupported field type: " + genericFieldType);
}
private void buildPrimitiveProperty(Class<?> fieldType, IPojoBuilder builder) {
builder.PrimitiveType(fieldType.getSimpleName());
}
private void buildReferenceProperty(Class<?> fieldType, IPojoBuilder builder) {
String name = fieldType.getName();
if (StringUtils.isWrapper(name))
builder.PrimitiveType(StringUtils.unboxFilter(name));
else {
builder.Annotations_();
builder.Modifier(ModifierEnum.DATATYPE);
builder._Annotations();
builder.ReferenceType(name);
}
}
private void buildArrayProperty(Type genericFieldType, IPojoBuilder builder) {
builder.ArrayType_();
if(genericFieldType instanceof GenericArrayType) {
Type componentType = ((GenericArrayType)genericFieldType).getGenericComponentType();
buildProperty(componentType, builder);
} else if (genericFieldType instanceof Class<?>) {
buildProperty(((Class<?>)genericFieldType).getComponentType(), builder);
}
builder._ArrayType();
}
private void buildCollectionProperty(Type genericFieldType, IPojoBuilder builder) {
builder.CollectionType_();
if (genericFieldType instanceof ParameterizedType) {
for (Type atype : ((ParameterizedType)genericFieldType).getActualTypeArguments()) {
Class<?> rawType = (Class<?>) ((ParameterizedType)genericFieldType).getRawType();
if (List.class.equals(rawType))
builder.CollectionInterface(CollectionInterfaceEnum.List);
else if (Set.class.equals(rawType))
builder.CollectionInterface(CollectionInterfaceEnum.Set);
else
builder.CollectionInterface(CollectionInterfaceEnum.Collection);
buildProperty(atype, builder);
}
} else {
if (List.class.equals((Class<?>)genericFieldType))
builder.CollectionInterface(CollectionInterfaceEnum.List);
else if (Set.class.equals((Class<?>)genericFieldType))
builder.CollectionInterface(CollectionInterfaceEnum.Set);
else
builder.CollectionInterface(CollectionInterfaceEnum.Collection);
buildProperty(Object.class, builder);
}
builder._CollectionType();
}
private void buildMapProperty(Type genericFieldType, IPojoBuilder builder) {
builder.MapType_();
if (genericFieldType instanceof ParameterizedType) {
for (Type atype : ((ParameterizedType)genericFieldType).getActualTypeArguments()) {
buildProperty(atype, builder);
}
} else {
buildProperty(Object.class, builder);
buildProperty(Object.class, builder);
}
builder._MapType();
}
}