/* * Copyright 2008-2017 the original author or authors. * * 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 org.codehaus.griffon.compile.core.ast.transform; import griffon.core.GriffonApplication; import org.codehaus.griffon.compile.core.ast.GriffonASTUtils; import org.codehaus.groovy.ast.AnnotationNode; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.FieldExpression; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; import java.lang.reflect.Modifier; import static griffon.util.GriffonNameUtils.getGetterName; import static griffon.util.GriffonNameUtils.isBlank; import static java.lang.reflect.Modifier.isPrivate; import static java.util.Objects.requireNonNull; import static org.codehaus.griffon.compile.core.ast.GriffonASTUtils.NO_ARGS; import static org.codehaus.griffon.compile.core.ast.GriffonASTUtils.NO_PARAMS; import static org.codehaus.griffon.compile.core.ast.GriffonASTUtils.THIS; import static org.codehaus.griffon.compile.core.ast.GriffonASTUtils.call; import static org.codehaus.groovy.ast.expr.VariableExpression.THIS_EXPRESSION; /** * @author Andres Almiray * @since 2.0.0 */ public abstract class AbstractASTInjector implements ASTInjector { public static final ClassNode NAMED_TYPE = makeClassSafe(Named.class); private static final ClassNode THREAD_TYPE = ClassHelper.make(Thread.class).getPlainNodeReference(); private static final ClassNode GRIFFON_APPLICATION_TYPE = makeClassSafe(GriffonApplication.class); private static final ClassNode INJECT_TYPE = makeClassSafe(Inject.class); private static final String PROPERTY_APPLICATION = "application"; private static final String METHOD_GET_APPLICATION = "getApplication"; @Nonnull public static ClassNode makeClassSafe(@Nonnull ClassNode classNode) { requireNonNull(classNode, "Argument 'classNode' must not be null"); return classNode.getPlainNodeReference(); } @Nonnull public static ClassNode makeClassSafe(@Nonnull Class<?> klass) { requireNonNull(klass, "Argument 'klass' must not be null"); return makeClassSafe(ClassHelper.make(klass)); } @Nonnull public static Expression currentThread() { return call(THREAD_TYPE, "currentThread", NO_ARGS); } @Nonnull public static Expression myClass() { return call(THIS_EXPRESSION, "getClass", NO_ARGS); } @Nonnull public static Expression myClassLoader() { return call(myClass(), "getClassLoader", NO_ARGS); } @Nonnull public static Expression applicationExpression(@Nonnull ClassNode classNode) { FieldNode field = classNode.getDeclaredField(PROPERTY_APPLICATION); if (field != null) { return new FieldExpression(field); } field = classNode.getField(PROPERTY_APPLICATION); if (field != null && !isPrivate(field.getModifiers())) { return new FieldExpression(field); } MethodNode method = classNode.getDeclaredMethod(METHOD_GET_APPLICATION, NO_PARAMS); if (method != null) { return call(THIS, METHOD_GET_APPLICATION, NO_ARGS); } method = classNode.getMethod(METHOD_GET_APPLICATION, NO_PARAMS); if (method != null && !isPrivate(method.getModifiers())) { return call(THIS, METHOD_GET_APPLICATION, NO_ARGS); } throw new IllegalStateException("Cannot resolve application field nor getApplication() method on class " + classNode.getName()); } @Nonnull public static Expression applicationProperty(@Nonnull ClassNode classNode, @Nonnull String property) { return call(applicationExpression(classNode), getGetterName(property), NO_ARGS); } @Nonnull public static FieldExpression injectedField(@Nonnull ClassNode owner, @Nonnull ClassNode type, @Nonnull String name) { return injectedField(owner, type, name, null); } @Nonnull public static FieldExpression injectedField(@Nonnull ClassNode owner, @Nonnull ClassNode type, @Nonnull String name, @Nullable String qualifierName) { FieldNode fieldNode = GriffonASTUtils.injectField(owner, name, Modifier.PRIVATE, type, null, false); if (fieldNode.getAnnotations(INJECT_TYPE) == null) { fieldNode.addAnnotation(new AnnotationNode(INJECT_TYPE)); } if (!isBlank(qualifierName) && fieldNode.getAnnotations(NAMED_TYPE) == null) { AnnotationNode namedAnnotation = new AnnotationNode(NAMED_TYPE); namedAnnotation.addMember("value", new ConstantExpression(qualifierName)); fieldNode.addAnnotation(namedAnnotation); } return new FieldExpression(fieldNode); } }