xapi.dev.generators.InstanceInjectionGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xapi-gwt-inject Show documentation
Show all versions of xapi-gwt-inject Show documentation
In order to implement the core XApi dependency injection in gwt,
we had to swap out the injection methods themselves with magic methods
that call into generated-on-the-fly provider classes.
/*
* Copyright 2012, We The Internet Ltd.
*
* All rights reserved.
*
* Distributed under a modified BSD License as follow:
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution, unless otherwise
* agreed to in a written document signed by a director of We The Internet Ltd.
*
* Neither the name of We The Internet nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package xapi.dev.generators;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;
import xapi.annotation.inject.InstanceDefault;
import xapi.annotation.inject.InstanceOverride;
import xapi.dev.util.CurrentGwtPlatform;
import xapi.platform.Platform;
import xapi.source.read.SourceUtil;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.RebindMode;
import com.google.gwt.core.ext.RebindResult;
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.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
public class InstanceInjectionGenerator extends AbstractInjectionGenerator {
/**
* @throws ClassNotFoundException
*/
public static RebindResult execImpl(TreeLogger logger, GeneratorContext context, JClassType type)
throws ClassNotFoundException {
JClassType targetType = type;
InstanceOverride winningOverride = null;
JClassType winningType = null;
// Step one: determine what platform we are targeting.
Set> allowedPlatforms = getPlatforms(context);
boolean trace = logger.isLoggable(Type.TRACE);
if (trace) {
logger.log(Type.TRACE, "Allowed platforms: "+allowedPlatforms);
logger.log(Type.TRACE, "All Subtypes: " + Arrays.asList(type.getSubtypes()));
}
for (JClassType subtype : type.getSubtypes()) {
if (trace)
logger.log(Type.TRACE, "Type "+subtype.getJNISignature());
InstanceDefault def = subtype.getAnnotation(InstanceDefault.class);
if (def != null) {
if (winningType != null)
continue; // a default cannot possibly override anything.
// Make sure this type is not excluded by being part of a disallowed platform
boolean useType = true;
for (Annotation anno : def.annotationType().getAnnotations()) {
if (anno.annotationType().getAnnotation(Platform.class) != null) {
if (allowedPlatforms.contains(anno.annotationType())) {
winningType = subtype;
continue;
}
useType = false;
}
}
// If we made it through without continue, or setting useType to false,
// then there is no platform specified, and this is a global default type.
if (useType)
winningType = subtype;
}
InstanceOverride override = subtype.getAnnotation(InstanceOverride.class);
if (override != null) {
// Prefer GwtPlatform or GwtDevPlatform,
// and blacklist any types that are of a foreign platform type (non-gwt).
boolean hasGwt = false, hasOther = false;
for (Annotation annotation : subtype.getAnnotations()){
// check each annotation to see if it is qualified with @Platform.
Platform platform = annotation.annotationType().getAnnotation(Platform.class);
if (platform != null) {
// When platform is non-null, we only want to use it if it's in our allowed list.
if (allowedPlatforms.contains(annotation.annotationType())) {
hasGwt = true;
break;
}else {
hasOther = true;
}
}
}
// if hasOther is false, or hasGwt is true, we want to use this type.
if (hasOther && !hasGwt) {
continue;
}
if (trace)
logger.log(Type.DEBUG, "Test subtype match " + subtype + " - prodMode: " + context.isProdMode());
if (winningOverride != null) {
if (winningOverride.priority() > override.priority()) continue;
}
winningOverride = override;
winningType = subtype;
}
}
if (winningType == null) {
winningType = targetType;// no matches, resort to instantiate the class sent.
if (trace)
logger.log(Type.TRACE, "No match made; resorting to GWT.create() on " + winningType+ " : ");
}
String packageName = type.getPackage().getName();
ensureProviderClass(logger, packageName, type.getSimpleSourceName(), type.getQualifiedSourceName(),
SourceUtil.toSourceName(winningType.getQualifiedSourceName()), context);
logger.log(Type.INFO,
"Instance injection: " + type.getQualifiedSourceName() + " -> " + winningType.getQualifiedSourceName());
return new RebindResult(RebindMode.USE_ALL_NEW_WITH_NO_CACHING, winningType.getQualifiedSourceName());
}
private static Set> getPlatforms(GeneratorContext ctx) {
return CurrentGwtPlatform.getPlatforms(ctx);
}
@Override
public RebindResult generateIncrementally(TreeLogger logger, GeneratorContext context, String typeName)
throws UnableToCompleteException {
TypeOracle oracle = context.getTypeOracle();
logger = logger.branch(Type.INFO, "Generating instance injection for " + typeName);
try {
return execImpl(logger, context, oracle.getType(SourceUtil.toSourceName(typeName)));
} catch (NotFoundException e) {
logger.log(Type.ERROR, "Could not find class for " + typeName, e);
} catch (ClassNotFoundException e) {
logger.log(Type.ERROR, "Could not find class for " + typeName, e);
}
throw new UnableToCompleteException();
}
}