com.emitrom.touch4j.rebind.BeanModelGenerator Maven / Gradle / Ivy
The newest version!
/************************************************************************
BeanModelGenerator.java is part of Touch4j 4.2.2.1 Copyright 2013 Emitrom LLC
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 com.emitrom.touch4j.rebind;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.emitrom.touch4j.client.core.FastMap;
import com.emitrom.touch4j.client.data.BeanModel;
import com.emitrom.touch4j.client.data.BeanModelFactory;
import com.emitrom.touch4j.client.data.BeanModelLookup;
import com.emitrom.touch4j.client.data.BeanModelMarker;
import com.emitrom.touch4j.client.data.BeanModelMarker.BEAN;
import com.emitrom.touch4j.client.data.BeanModelTag;
import com.emitrom.touch4j.client.data.NestedModelUtil;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
public class BeanModelGenerator extends Generator {
protected TypeOracle oracle;
protected JClassType beanModelMarkerType;
protected JClassType beanModelTagType;
protected List beans;
@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
oracle = context.getTypeOracle();
beanModelMarkerType = oracle.findType(BeanModelMarker.class.getName());
beanModelTagType = oracle.findType(BeanModelTag.class.getName());
try {
// final all beans and bean markers
beans = new ArrayList();
JClassType[] types = oracle.getTypes();
for (JClassType type : types) {
if (isBeanMarker(type)) {
beans.add(getMarkerBean(type));
} else if (isBean(type)) {
beans.add(type);
}
}
final String genPackageName = BeanModelLookup.class.getPackage()
.getName();
final String genClassName = "BeanModelLookupImpl";
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
genPackageName, genClassName);
composer.setSuperclass(BeanModelLookup.class.getCanonicalName());
composer.addImport(BeanModelFactory.class.getName());
composer.addImport(Map.class.getName());
composer.addImport(FastMap.class.getName());
PrintWriter pw = context.tryCreate(logger, genPackageName,
genClassName);
if (pw != null) {
SourceWriter sw = composer.createSourceWriter(context, pw);
sw.println("private Map m;");
sw.println("public BeanModelFactory getFactory(Class b) {");
sw.indent();
sw.println("String n = b.getName();");
sw.println("if (m == null) {");
sw.indentln("m = new FastMap();");
sw.println("}");
sw.println("if (m.get(n) == null) {");
sw.indent();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < beans.size(); i++) {
JClassType bean = beans.get(i);
String name = createBean(bean, logger, context);
String factory = createFactory(bean, name, logger, context);
if (i > 0) {
sw.print(" else ");
}
sw.println("if (" + bean.getQualifiedSourceName()
+ ".class.getName().equals(n)) {");
sw.indentln("m" + i + "();");
sb.append("private void m" + i + "() {\n");
sb.append(" m.put(" + bean.getQualifiedSourceName()
+ ".class.getName(), new " + factory + "());\n");
sb.append("}\n");
sw.print("}");
}
sw.outdent();
sw.println("}");
sw.println("return m.get(n);");
sw.outdent();
sw.println("}");
sw.println(sb.toString());
sw.commit(logger);
}
return composer.getCreatedClassName();
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "Class " + typeName + " not found.", e);
throw new UnableToCompleteException();
}
}
protected String createFactory(JClassType bean, String beanModelName,
TreeLogger logger, GeneratorContext context) throws Exception {
final String genPackageName = BeanModelLookup.class.getPackage()
.getName();
final String genClassName = "BeanModel_"
+ bean.getQualifiedSourceName().replace(".", "_") + "_Factory";
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
genPackageName, genClassName);
composer.setSuperclass(BeanModelFactory.class.getCanonicalName());
PrintWriter pw = context
.tryCreate(logger, genPackageName, genClassName);
if (pw != null) {
List getters = findGetters(bean);
String typeName = bean.getQualifiedSourceName();
SourceWriter sw = composer.createSourceWriter(context, pw);
sw.println("public BeanModel newInstance() {");
sw.println("return new " + beanModelName + "();");
sw.println("}");
sw.println("public BeanModel createModel(Object bean) {");
sw.println("BeanModel model = newInstance();");
for (JMethod method : getters) {
String s = method.getName();
String p = lowerFirst(s.substring(s.startsWith("g") ? 3 : 2)); // get
sw.println("model.set(\"" + p + "\"," + " ((" + typeName
+ ")bean)." + s + "()" + ");");
}
sw.println("model.setBean(bean);");
sw.println("return model;");
sw.println("}");
sw.commit(logger);
}
return composer.getCreatedClassName();
}
protected String createBean(JClassType bean, TreeLogger logger,
GeneratorContext context) throws Exception {
final String genPackageName = bean.getPackage().getName();
final String genClassName = "BeanModel_"
+ bean.getQualifiedSourceName().replace(".", "_");
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
genPackageName, genClassName);
composer.setSuperclass(BeanModel.class.getCanonicalName());
composer.addImport(BeanModel.class.getName());
composer.addImport(NestedModelUtil.class.getName());
PrintWriter pw = context
.tryCreate(logger, genPackageName, genClassName);
if (pw != null) {
List getters = findGetters(bean);
List setters = findSetters(bean);
SourceWriter sw = composer.createSourceWriter(context, pw);
sw.println("public " + genClassName + "(){");
for (JMethod method : getters) {
String s = method.getName();
String p = lowerFirst(s.substring(s.startsWith("g") ? 3 : 2)); // get
// or
// is
sw.println("beanProperties.add(\"" + p + "\");");
}
sw.println("}");
createGetMethods(getters, sw, bean.getQualifiedSourceName());
createSetMethods(setters, sw, bean.getQualifiedSourceName());
// delegate equals to bean
sw.println("public boolean equals(Object obj) {");
sw.println(" if (obj instanceof " + "BeanModel" + ") {");
sw.println(" obj = ((BeanModel)obj).getBean();");
sw.println(" }");
sw.println(" return bean.equals(obj);");
sw.println("}");
// delegate hashCode to bean
sw.println("public int hashCode(){");
sw.println(" return bean.hashCode();");
sw.println("}");
sw.commit(logger);
}
return composer.getCreatedClassName();
}
protected JClassType getMarkerBean(JClassType type)
throws NotFoundException {
BEAN pojo = type.getAnnotation(BEAN.class);
return oracle.getType(pojo.value().getCanonicalName());
}
protected boolean isBean(JClassType type) {
return !type.equals(beanModelTagType)
&& type.isAssignableTo(beanModelTagType);
}
protected boolean isBeanMarker(JClassType type) {
return !type.equals(beanModelMarkerType)
&& type.isAssignableTo(beanModelMarkerType);
}
protected void createGetMethods(List getters, SourceWriter sw,
String typeName) {
sw.println("public X getPropertyAsString(String s) {");
sw.println("if (allowNestedValues && NestedModelUtil.isNestedProperty(s)) {");
sw.indentln("return (X)NestedModelUtil.getNestedValue(this, s);");
sw.println("}");
for (JMethod method : getters) {
JClassType returnType = method.getReturnType().isClassOrInterface();
String s = method.getName();
String p = lowerFirst(s.substring(s.startsWith("g") ? 3 : 2)); // get
// or
sw.println("if (s.equals(\"" + p + "\")) {");
sw.println("Object value = ((" + typeName + ")bean)." + s + "();");
try {
if (returnType != null
&& returnType.isAssignableTo(oracle.getType(List.class
.getName()))
&& returnType.isParameterized() != null) {
JParameterizedType type = returnType.isParameterized();
JClassType[] params = type.getTypeArgs();
if (beans.contains(params[0])) {
sw.println("if (value != null) {");
sw.indent();
sw.println("java.util.List list = (java.util.List)value;");
sw.println("java.util.List list2 = "
+ BeanModelLookup.class.getCanonicalName()
+ ".get().getFactory("
+ params[0].getQualifiedSourceName()
+ ".class).createModel((java.util.Collection) list);");
sw.outdent();
sw.println("return (X) list2;");
sw.println("}");
}
} else {
// swap returnType as generic types were not matching
// (beans.contains(returnType))
if (returnType != null) {
String t = returnType.getQualifiedSourceName();
if (t.indexOf("extends") == -1) {
returnType = oracle.getType(t);
}
}
if (beans.contains(returnType)) {
sw.println("if (value != null) {");
sw.println(" BeanModel nestedModel = nestedModels.get(s);");
sw.println(" if (nestedModel != null) {");
sw.println(" Object bean = nestedModel.getBean();");
sw.println(" if (!bean.equals(value)){");
sw.println(" nestedModel = null;");
sw.println(" }");
sw.println(" }");
sw.println(" if (nestedModel == null) {");
sw.println(" nestedModel = "
+ BeanModelLookup.class.getCanonicalName()
+ ".get().getFactory("
+ returnType.getQualifiedSourceName()
+ ".class).createModel(value);");
sw.println(" nestedModels.put(s, nestedModel);");
sw.println(" }");
sw.println(" return (X)processValue(nestedModel);");
sw.println("}");
}
}
} catch (Exception e) {
e.printStackTrace();
}
sw.println("return (X)processValue(value);");
sw.println("}");
}
sw.println("return super.getFromCache(s);");
sw.println("}");
}
protected String lowerFirst(String propName) {
if (propName.length() == 0) {
return propName;
} else if (propName.length() == 1) {
return propName.toLowerCase();
} else {
return propName.substring(0, 1).toLowerCase()
+ propName.substring(1);
}
}
protected String getMethodAttributeType(JMethod method) {
return method.getParameters()[0].getType().getQualifiedSourceName();
}
protected void createSetMethods(List properties, SourceWriter sw,
String typeName) {
sw.println("public X setProperty(String s, X val) {");
sw.indent();
sw.println("Object obj = val;");
sw.println("if (obj instanceof BeanModel) {");
sw.println("obj = ((BeanModel) obj).getBean();");
sw.println("} else if (obj instanceof java.util.List) {");
sw.println("java.util.List list = new java.util.ArrayList();");
sw.println("for(Object o : (java.util.List) obj) {");
sw.println("if(o instanceof BeanModel) {");
sw.println("list.add(((BeanModel) o).getBean());");
sw.println("} else {");
sw.println("list.add(o);");
sw.println("}");
sw.println("}");
sw.println("obj = list;");
sw.println("}");
sw.println("if (allowNestedValues && val instanceof BeanModel) {");
sw.indent();
sw.println("obj = ((BeanModel)val).getBean();");
sw.println("if (nestedModels.containsKey(s)) {");
sw.indent();
sw.println("nestedModels.put(s, (BeanModel)val);");
sw.outdent();
sw.println("}");
sw.outdent();
sw.println("}");
sw.println("if (allowNestedValues && NestedModelUtil.isNestedProperty(s)) {");
sw.indent();
sw.println("X old = (X) NestedModelUtil.setNestedValue(this, s, val);");
sw.println("notifyPropertyChanged(s, val, old);");
sw.println("return old;");
sw.outdent();
sw.println("}");
for (JMethod method : properties) {
String s = method.getName();
String p = lowerFirst(s.substring(3));
String type = getMethodAttributeType(method);
if (type.indexOf("extends") != -1) {
type = "java.lang.Object";
}
if (type.equals("byte")) {
type = "Byte";
} else if (type.equals("char")) {
type = "Character";
} else if (type.equals("short")) {
type = "Short";
} else if (type.equals("int")) {
type = "Integer";
} else if (type.equals("long")) {
type = "Long";
} else if (type.equals("float")) {
type = "Float";
} else if (type.equals("double")) {
type = "Double";
} else if (type.equals("boolean")) {
type = "Boolean";
}
sw.println("if (s.equals(\"" + p + "\")) {");
sw.indent();
sw.println("Object old = get(s);");
sw.println("((" + typeName + ")bean)." + s + "((" + type + ")obj);");
sw.println("notifyPropertyChanged(s, val, old);");
sw.println("return (X)old;");
sw.outdent();
sw.println("}");
}
sw.println("return super.set(s, val);");
sw.outdent();
sw.println("}");
}
protected List findGetters(JClassType cls) {
List methods = new ArrayList();
addGetters(cls, methods);
return methods;
}
protected void addGetters(JClassType cls, List methods) {
if (cls == null) {
return;
}
// ignore methods of Object
if (cls.isInterface() != null || cls.getSuperclass() != null) {
addGetters(cls.getSuperclass(), methods);
for (JMethod m : cls.getMethods()) {
if (m.isPublic() || m.isProtected()) {
String name = m.getName();
if ((name.matches("get.*") || name.matches("is.*"))
&& m.getParameters().length == 0) {
methods.add(m);
}
}
}
}
}
protected List findSetters(JClassType cls) {
List methods = new ArrayList();
addSetters(cls, methods);
return methods;
}
protected void addSetters(JClassType cls, List methods) {
if (cls.getSuperclass() != null) {
addSetters(cls.getSuperclass(), methods);
}
for (JMethod m : cls.getMethods()) {
if (m.isPublic() || m.isProtected()) {
String name = m.getName();
if (name.matches("set.*") && m.getParameters().length == 1) {
methods.add(m);
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy