com.gafactory.core.rebind.ValueProviderCreator.java Source code

Java tutorial

Introduction

Here is the source code for com.gafactory.core.rebind.ValueProviderCreator.java

Source

/**
 * Sencha GXT 3.0.1 - Sencha for GWT
 * Copyright(c) 2007-2012, Sencha, Inc.
 * licensing@sencha.com
 *
 * http://www.sencha.com/products/gxt/license/
 */
package com.gafactory.core.rebind;

import com.google.common.base.Joiner;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JGenericType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.dev.util.Name;
import com.google.gwt.editor.client.Editor.Path;
import com.google.gwt.editor.rebind.model.ModelUtils;
import com.google.gwt.user.rebind.SourceWriter;
import com.gafactory.core.shared.ValueProvider;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("UnusedAssignment")
public class ValueProviderCreator extends AbstractCreator {
    public enum RequiredReadability {
        BOTH, SET, GET, NEITHER
    }

    protected static String cap(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    private static List<String> generatePath(Path annotation, String name) {
        if (annotation == null) {
            return Collections.singletonList(name);
        }
        return Arrays.asList(annotation.value().split("\\."));
    }

    private final JClassType supertypeToImplement;

    protected final List<String> path;

    private final JGenericType valueProviderInterface = getContext().getTypeOracle()
            .findType(Name.getSourceNameForClass(ValueProvider.class)).isGenericType();

    private RequiredReadability readability = RequiredReadability.NEITHER;

    public ValueProviderCreator(GeneratorContext ctx, TreeLogger l, JMethod valueProviderMethodDecl) {
        super(ctx, l);
        this.supertypeToImplement = valueProviderMethodDecl.getReturnType().isClassOrInterface();
        this.path = generatePath(valueProviderMethodDecl.getAnnotation(Path.class),
                valueProviderMethodDecl.getName());
    }

    public ValueProviderCreator(GeneratorContext ctx, TreeLogger l, List<String> path, JClassType baseType,
            JClassType valueType) {
        super(ctx, l);
        this.path = path;
        supertypeToImplement = getContext().getTypeOracle().getParameterizedType(valueProviderInterface,
                new JClassType[] { baseType, valueType });
    }

    @Override
    public String getInstanceExpression() {
        return getPackageName() + "." + getSimpleName() + ".INSTANCE";
    }

    public void setReadability(RequiredReadability readability) {
        this.readability = readability;
    }

    @Override
    protected void create(SourceWriter sw) throws UnableToCompleteException {
        sw.println("public static final %1$s INSTANCE = new %1$s();", getSimpleName());
        // @Override
        sw.println("public %1$s getValue(%2$s object) {", getValueTypeName(), getObjectTypeName());
        String getter = getGetterExpression("object");
        if (getter == null) {
            if (readability == RequiredReadability.NEITHER || readability == RequiredReadability.SET) {
                // getter is not required, but log it if someone tries to call it
                getLogger().log(Type.DEBUG,
                        "Getter could not be found (and apparently not needed), writting a log message to indicate that this is probably an error.");
                sw.indentln("com.google.gwt.core.client.GWT.log(\"Getter was called on "
                        + supertypeToImplement.getName() + ", but no getter exists.\", new RuntimeException());");
                sw.indentln("return null;");
            } else {
                getLogger().log(Type.ERROR, "No getter can be found, unable to proceed");
                throw new UnableToCompleteException();
            }
        } else {
            sw.indentln("return %1$s;", getter);
        }
        sw.println("}");

        // @Override
        sw.println("public void setValue(%1$s object, %2$s value) {", getObjectTypeName(), getValueTypeName());
        String setter = getSetterExpression("object", "value");
        if (setter == null) {
            if (readability == RequiredReadability.NEITHER || readability == RequiredReadability.GET) {
                // setter is not required, but log it if someone tries to call it
                getLogger().log(Type.DEBUG,
                        "Setter could not be found (and apparently not needed), writing a log message to indicate that this is probably an error.");
                sw.indentln("com.google.gwt.core.client.GWT.log(\"Setter was called on "
                        + supertypeToImplement.getName() + ", but no setter exists.\", new RuntimeException());");
            } else {
                getLogger().log(Type.ERROR, "No setter can be found, unable to proceed");
                throw new UnableToCompleteException();
            }
        } else {
            sw.indentln("%1$s;", setter);
        }
        sw.println("}");

        // @Override
        sw.println("public String getPath() {");
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String p : path) {
            if (!first) {
                sb.append(".");
            }
            sb.append(p);

            first = false;
        }
        sw.indentln("return \"%1$s\";", sb.toString());
        sw.println("}");
    }

    protected String getGetterExpression(String objectName) {
        StringBuilder sb = new StringBuilder(objectName);
        try {
            getGetterHelper(path, sb);
        } catch (NoSuchMethodException ex) {
            return null;
        }
        return sb.toString();
    }

    protected JMethod getMethod(JClassType type, String methodName) {
        JMethod[] methods = type.getInheritableMethods();
        for (JMethod m : methods) {
            if (m.getName().equals(methodName)) {
                return m;
            }
        }
        return null;
    }

    /**
     * Gets the type of the Model this object should provide data for.
     * 
     * @return the parameterized type of the model
     */
    protected JClassType getObjectType() {
        JClassType[] params = ModelUtils.findParameterizationOf(valueProviderInterface, supertypeToImplement);

        if (params[0].isTypeParameter() != null) {
            return params[0].isTypeParameter().getBaseType();
        } else {
            return params[0];
        }
    }

    /**
     * Evaluated when used so this can be subclassed, and used for generating
     * similar types
     * 
     * @return the parameterized qualified name
     */
    protected final String getObjectTypeName() {
        return getObjectType().getParameterizedQualifiedSourceName();
    }

    @Override
    protected String getPackageName() {
        return getObjectType().getPackage().getName();
    }

    @Override
    protected String getSimpleName() {
        return getObjectType().getName().replace('.', '_') + "_"
                + Joiner.on("_").join(path.toArray(new String[path.size()])) + "_ValueProviderImpl";
    }

    @Override
    protected JClassType getSupertype() {
        return supertypeToImplement;
    }

    /**
     * Helper method for building up chained getter expressions
     * 
     * @param path the path to follow to find the next getter
     * @param sb stringbuild to append the methods to
     * @return the type returned of the last method
     * @throws NoSuchMethodException if a method cannot be found
     */
    private JClassType getGetterHelper(List<String> path, StringBuilder sb) throws NoSuchMethodException {
        JClassType type = getObjectType();
        for (String p : path) {
            if (type == null) {
                getLogger().log(Type.WARN, "Trying to find a method in a non-class, non-interface type.");
            }
            // TODO field?
            // TODO is, has

            // Pick a method to use
            JMethod method = getMethod(type, p);
            if (method == null) {
                method = getMethod(type, "get" + cap(p));
            }
            if (method == null) {
                method = getMethod(type, "is" + cap(p));
            }
            if (method == null) {
                method = getMethod(type, "has" + cap(p));
            }
            if (method == null) {
                getLogger().log(Type.WARN, "Method get" + cap(p) + " could not be found");
                throw new NoSuchMethodException();
            }

            sb.append(".").append(method.getName()).append("()");

            type = method.getReturnType().isClassOrInterface();
        }
        return type;
    }

    private String getSetterExpression(String objectName, String valueName) {
        StringBuilder sb = new StringBuilder(objectName);

        // find the getter from the start of the path
        List<String> getterPath = this.path.subList(0, this.path.size() - 1);
        JClassType type = null;
        try {
            type = getGetterHelper(getterPath, sb);
        } catch (NoSuchMethodException ex) {
            return null;
        }
        if (type == null) {
            getLogger().log(Type.WARN, "Trying to find setter method on a non-class, non-interface type ");
            return null;
        }
        String methodName = "set" + cap(path.get(path.size() - 1));
        sb.append(".").append(methodName).append("(").append(valueName).append(")");
        if (null == getMethod(type, methodName)) {
            getLogger().log(Type.DEBUG, "Method " + methodName + " could not be found ");
            return null;
        }

        return sb.toString();
    }

    private JClassType getValueType() {
        JClassType[] params = ModelUtils.findParameterizationOf(valueProviderInterface, supertypeToImplement);

        return params[1];
    }

    private String getValueTypeName() {
        return getValueType().getParameterizedQualifiedSourceName();
    }
}