Package com.gwtplatform.dispatch.annotation.processor

Source Code of com.gwtplatform.dispatch.annotation.processor.GenProxyProcessor

/**
* Copyright 2011 ArcBees Inc.
*
* 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.gwtplatform.dispatch.annotation.processor;

import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;

import com.google.web.bindery.requestfactory.shared.Locator;
import com.gwtplatform.dispatch.annotation.GenProxy;
import com.gwtplatform.dispatch.annotation.UseProxy;
import com.gwtplatform.dispatch.annotation.UseProxyName;
import com.gwtplatform.dispatch.annotation.helper.InterfaceGenerationHelper;
import com.gwtplatform.dispatch.annotation.helper.ReflectionHelper;

/**
* Processes {@link GenProxy} annotations.
* <p/>
* {@link GenProxyProcessor} should only ever be called by tool infrastructure.
* See {@link javax.annotation.processing.Processor} for more details.
*/
@SupportedAnnotationTypes("com.gwtplatform.dispatch.annotation.GenProxy")
public class GenProxyProcessor extends GenProcessor {
    @Override
    public void process(final Element proxyElement) {
        GenProxy genProxy = proxyElement.getAnnotation(GenProxy.class);
        generateProxy(
                proxyElement,
                genProxy.targetPackage(),
                genProxy.filterSetter(),
                genProxy.filterGetter(),
                genProxy.isEmbeddedType(),
                getLocatorTypeMirror(genProxy)
        );
    }

    protected void generateProxy(Element proxyElement, String targetPackage, String[] filterSetter,
            String[] filterGetter, boolean isEmbeddedType, TypeMirror locatorType) {
        InterfaceGenerationHelper writer = null;
        try {
            ReflectionHelper reflection = new ReflectionHelper(getEnvironment(), (TypeElement) proxyElement);
            String proxyElementSimpleName = reflection.getSimpleClassName();
            String proxyElementClassName = reflection.getClassName();
            String proxyElementPackage = reflection.getPackageName();

            // Magic: By default proxies should be available for client and server side.
            String preparedProxyElementClassName = proxyElementClassName.replace(".server", ".shared");
            String preparedProxyElementPackage = proxyElementPackage.replace(".server", ".shared");

            if (targetPackage != null && !targetPackage.isEmpty()) {
                // Prepare user defined proxy target package and do not replace server with shared.
                preparedProxyElementClassName = targetPackage + "." + proxyElementSimpleName;
                preparedProxyElementPackage = targetPackage;
            }

            String proxySimpleName = proxyElementSimpleName + "Proxy";
            String proxyClassName = preparedProxyElementClassName + "Proxy";

            @SuppressWarnings("resource")
            Writer sourceWriter = getEnvironment().getFiler().createSourceFile(proxyClassName,
                    proxyElement).openWriter();
            writer = new InterfaceGenerationHelper(sourceWriter);
            writer.generatePackageDeclaration(preparedProxyElementPackage);

            if (isEmbeddedType) {
                generateValueProxyHeader(writer, reflection, proxyElementClassName, proxySimpleName);
            } else {
                generateEntityProxyHeader(writer, reflection, proxyElementClassName, proxySimpleName, locatorType);
            }

            writer.println();

            Collection<VariableElement> allFields = reflection.getNonConstantFields();

            // Generate getters.
            Collection<VariableElement> getterFields = reflection.filterFields(allFields, filterGetter);
            for (VariableElement getterField : getterFields) {
                generateGetter(writer, getterField);
            }

            // Generate setters.
            Collection<VariableElement> setterFields = reflection.filterFields(allFields, filterSetter);
            for (VariableElement setterField : setterFields) {
                generateSetter(writer, setterField);
            }

            writer.println();
            writer.generateFooter();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    protected void generateEntityProxyHeader(InterfaceGenerationHelper writer, ReflectionHelper reflection,
            String proxyElementClassName, String proxySimpleName, TypeMirror locatorType) {
        writer.generateImports(
                "com.google.web.bindery.requestfactory.shared.ProxyFor",
                "com.google.web.bindery.requestfactory.shared.EntityProxy",
                "com.google.web.bindery.requestfactory.shared.EntityProxyId"
        );
        writer.println();
        // Check for locator.
        if (locatorType == null || Locator.class.getName().equals(locatorType.toString())) {
            writer.generateAnnotation("ProxyFor", proxyElementClassName + ".class");
        } else {
            writer.println("@{0}(value = {1}.class, locator = {2}.class)",
                    "ProxyFor", proxyElementClassName,
                    locatorType.toString());
        }
        writer.generateInterfaceHeader(proxySimpleName, reflection.getClassRepresenter().getModifiers(),
                "EntityProxy"
        );
        writer.println();
        writer.generateEmptyMethodBody("stableId", "EntityProxyId<" + proxySimpleName + ">");
    }

    protected void generateValueProxyHeader(InterfaceGenerationHelper writer, ReflectionHelper reflection,
            String proxyElementClassName, String proxySimpleName) {
        writer.generateImports(
                "com.google.web.bindery.requestfactory.shared.ProxyFor",
                "com.google.web.bindery.requestfactory.shared.ValueProxy"
        );
        writer.println();
        writer.generateAnnotation("ProxyFor", proxyElementClassName + ".class");
        writer.generateInterfaceHeader(proxySimpleName, reflection.getClassRepresenter().getModifiers(), "ValueProxy");
    }

    protected void generateGetter(InterfaceGenerationHelper writer, VariableElement getterField) {
        // Check for embedded types.
        UseProxy useProxyAnnotation = getterField.getAnnotation(UseProxy.class);
        UseProxyName useProxyNameAnnotation = getterField.getAnnotation(UseProxyName.class);
        if (useProxyAnnotation != null) {
            writer.generateGetter(getterField.getSimpleName().toString(), getProxyTypeMirrorName(useProxyAnnotation,
                    getterField.asType()));
        } else if (useProxyNameAnnotation != null) {
            writer.generateGetter(getterField.getSimpleName().toString(), useProxyNameAnnotation.value());
        } else {
            writer.generateGetter(getterField);
        }
    }

    protected void generateSetter(InterfaceGenerationHelper writer, VariableElement setterField) {
        // Check for embedded types.
        UseProxy useProxyAnnotation = setterField.getAnnotation(UseProxy.class);
        UseProxyName useProxyNameAnnotation = setterField.getAnnotation(UseProxyName.class);
        if (useProxyAnnotation != null) {
            writer.generateSetter(setterField.getSimpleName().toString(), getProxyTypeMirrorName(useProxyAnnotation,
                    setterField.asType()));
        } else if (useProxyNameAnnotation != null) {
            writer.generateSetter(setterField.getSimpleName().toString(), useProxyNameAnnotation.value());
        } else {
            writer.generateSetter(setterField);
        }
    }

    /**
     * Workaround for MirroredTypeException (Attempt to access Class object for TypeMirror).
     *
     * @see <a href="http://goo.gl/7ee2R">Getting class values from annotations in an annotationprocessor</a>
     */
    protected final String getProxyTypeMirrorName(UseProxy useProxyAnnotation, TypeMirror originalTypeMirror) {
        TypeMirror mirror = null;
        try {
            useProxyAnnotation.value();
        } catch (MirroredTypeException e) {
            mirror = e.getTypeMirror();
        }

        return nestIntoCollectionIfNecessary(mirror, originalTypeMirror);
    }

    private String nestIntoCollectionIfNecessary(TypeMirror mirror, TypeMirror originalTypeMirror) {
        String originalTypeDeclaration = originalTypeMirror.toString();

        // Shortcut if no generics can be found in the type declaration
        if (!(originalTypeDeclaration.contains("<") && originalTypeDeclaration.contains(">"))) {
            return mirror.toString();
        }

        String collectionClassName = originalTypeDeclaration.substring(0, originalTypeDeclaration.indexOf("<"));
        Class collectionClass = tryRetrieveCollectionClass(collectionClassName);

        StringBuilder builder = new StringBuilder();
        if (collectionClass != null && (isAssignableToSet(collectionClass) || isAssignableToList(collectionClass))) {
            builder.append(collectionClassName).append("<").append(mirror.toString()).append(">");
        } else {
            builder.append(mirror.toString());
        }
        return builder.toString();
    }

    private Class tryRetrieveCollectionClass(String collectionClassName) {
        try {
            return Class.forName(collectionClassName);
        } catch (ClassNotFoundException e) {
            printMessage("Potential collection class " + collectionClassName + " could not be found.");
        }
        return null;
    }

    private boolean isAssignableToSet(Class collectionClass) {
        if (collectionClass.equals(Set.class)) {
            return true;
        }
        for (Class interfaceClass : collectionClass.getInterfaces()) {
            if (interfaceClass.equals(Set.class)) {
                return true;
            }
        }
        return false;
    }

    private boolean isAssignableToList(Class collectionClass) {
        if (collectionClass.equals(List.class)) {
            return true;
        }
        for (Class interfaceClass : collectionClass.getInterfaces()) {
            if (interfaceClass.equals(List.class)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @see #getProxyTypeMirrorName(com.gwtplatform.dispatch.annotation.UseProxy, javax.lang.model.type.TypeMirror)
     */
    protected final TypeMirror getLocatorTypeMirror(GenProxy genProxyAnnotation) {
        TypeMirror mirror = null;
        try {
            genProxyAnnotation.locator();
        } catch (MirroredTypeException e) {
            mirror = e.getTypeMirror();
        }
        return mirror;
    }
}
TOP

Related Classes of com.gwtplatform.dispatch.annotation.processor.GenProxyProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.