All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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