Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.micronaut.ast.groovy.visitor.GroovyVisitorContext Maven / Gradle / Ivy
/*
* Copyright 2017-2020 original 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
*
* https://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 io.micronaut.ast.groovy.visitor;
import groovy.lang.GroovyClassLoader;
import io.micronaut.ast.groovy.GroovyNativeElementHelper;
import io.micronaut.ast.groovy.annotation.GroovyAnnotationMetadataBuilder;
import io.micronaut.ast.groovy.annotation.GroovyElementAnnotationMetadataFactory;
import io.micronaut.ast.groovy.scan.ClassPathAnnotationScanner;
import io.micronaut.ast.groovy.utils.AstMessageUtils;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.convert.value.MutableConvertibleValues;
import io.micronaut.core.convert.value.MutableConvertibleValuesMap;
import io.micronaut.core.reflect.ClassUtils;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.expressions.context.DefaultExpressionCompilationContextFactory;
import io.micronaut.expressions.context.ExpressionCompilationContextFactory;
import io.micronaut.inject.ast.ClassElement;
import io.micronaut.inject.ast.Element;
import io.micronaut.inject.ast.annotation.ElementAnnotationMetadataFactory;
import io.micronaut.inject.visitor.VisitorContext;
import io.micronaut.inject.visitor.util.VisitorContextUtils;
import io.micronaut.inject.writer.AbstractBeanDefinitionBuilder;
import io.micronaut.inject.writer.ClassWriterOutputVisitor;
import io.micronaut.inject.writer.GeneratedFile;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.control.ClassNodeResolver;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.Janitor;
import org.codehaus.groovy.control.SourceUnit;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* The visitor context when visiting Groovy code.
*
* @author James Kleeh
* @author Graeme Rocher
* @since 1.0
*/
@Internal
public class GroovyVisitorContext implements VisitorContext {
private static final MutableConvertibleValues VISITOR_ATTRIBUTES = new MutableConvertibleValuesMap<>();
private final CompilationUnit compilationUnit;
private final ClassWriterOutputVisitor outputVisitor;
private final SourceUnit sourceUnit;
private final MutableConvertibleValues attributes;
private final List generatedResources = new ArrayList<>();
private final GroovyElementFactory groovyElementFactory;
private final List beanDefinitionBuilders = new ArrayList<>();
private final GroovyElementAnnotationMetadataFactory elementAnnotationMetadataFactory;
private final ExpressionCompilationContextFactory expressionCompilationContextFactory;
private final GroovyNativeElementHelper nativeElementHelper;
private final GroovyAnnotationMetadataBuilder annotationMetadataBuilder;
/**
* @param sourceUnit The source unit
* @param compilationUnit The compilation unit
*/
public GroovyVisitorContext(SourceUnit sourceUnit, @Nullable CompilationUnit compilationUnit) {
this(sourceUnit, compilationUnit, new GroovyClassWriterOutputVisitor(compilationUnit));
}
/**
* @param sourceUnit The source unit
* @param compilationUnit The compilation unit
* @param outputVisitor The class writer output visitor
*/
public GroovyVisitorContext(SourceUnit sourceUnit, @Nullable CompilationUnit compilationUnit, ClassWriterOutputVisitor outputVisitor) {
this.sourceUnit = sourceUnit;
this.compilationUnit = compilationUnit;
this.outputVisitor = outputVisitor;
this.attributes = VISITOR_ATTRIBUTES;
this.nativeElementHelper = new GroovyNativeElementHelper();
this.groovyElementFactory = new GroovyElementFactory(this);
this.annotationMetadataBuilder = new GroovyAnnotationMetadataBuilder(sourceUnit, compilationUnit, nativeElementHelper, this);
this.elementAnnotationMetadataFactory = new GroovyElementAnnotationMetadataFactory(false, annotationMetadataBuilder);
this.expressionCompilationContextFactory = new DefaultExpressionCompilationContextFactory(this);
}
@Override
public Language getLanguage() {
return Language.GROOVY;
}
@NonNull
@Override
public Iterable getClasspathResources(@NonNull String path) {
try {
final Enumeration resources = compilationUnit.getClassLoader().getResources(path);
return CollectionUtils.enumerationToIterable(resources);
} catch (IOException e) {
return Collections.emptyList();
}
}
@Override
public Optional getClassElement(String name) {
return getClassElement(name, getElementAnnotationMetadataFactory());
}
@Override
public Optional getClassElement(String name, ElementAnnotationMetadataFactory annotationMetadataFactory) {
if (name == null) {
return Optional.empty();
} else if (compilationUnit == null) {
return Optional.ofNullable(classNodeFromClassLoader(name)).map(cn ->
groovyElementFactory.newClassElement(cn, annotationMetadataFactory)
);
}
ClassNodeResolver.LookupResult lookupResult = compilationUnit.getClassNodeResolver().resolveName(name, compilationUnit);
Optional classNode;
if (lookupResult != null) {
classNode = Optional.ofNullable(lookupResult.getClassNode());
} else {
classNode = Optional.ofNullable(compilationUnit.getClassNode(name));
}
ClassNode finalClassNode = classNode.orElseGet(() -> classNodeFromClassLoader(name));
return Optional.ofNullable(finalClassNode).map(cn -> groovyElementFactory.newClassElement(cn, annotationMetadataFactory));
}
private ClassNode classNodeFromClassLoader(String name) {
ClassNode cn = null;
if (sourceUnit != null) {
GroovyClassLoader classLoader = sourceUnit.getClassLoader();
if (classLoader != null) {
cn = ClassUtils.forName(name, classLoader).map(ClassHelper::make).orElse(null);
}
}
return cn;
}
@Override
public Optional getClassElement(Class> type) {
final ClassNode classNode = ClassHelper.makeCached(type);
return Optional.of(groovyElementFactory.newClassElement(classNode, getElementAnnotationMetadataFactory()));
}
@NonNull
@Override
public ClassElement[] getClassElements(@NonNull String aPackage, @NonNull String... stereotypes) {
ArgumentUtils.requireNonNull("aPackage", aPackage);
ArgumentUtils.requireNonNull("stereotypes", stereotypes);
if (compilationUnit == null) {
return ClassElement.ZERO_CLASS_ELEMENTS;
}
ClassPathAnnotationScanner scanner = new ClassPathAnnotationScanner(compilationUnit.getClassLoader());
List classElements = new ArrayList<>();
for (String s : stereotypes) {
scanner.scan(s, aPackage).forEach(aClass -> {
final ClassNode classNode = ClassHelper.make(aClass);
classElements.add(groovyElementFactory.newClassElement(classNode, getElementAnnotationMetadataFactory()));
});
}
return classElements.toArray(ClassElement.ZERO_CLASS_ELEMENTS);
}
@NonNull
@Override
public GroovyElementFactory getElementFactory() {
return groovyElementFactory;
}
@NonNull
@Override
public GroovyElementAnnotationMetadataFactory getElementAnnotationMetadataFactory() {
return elementAnnotationMetadataFactory;
}
@Override
public ExpressionCompilationContextFactory getExpressionCompilationContextFactory() {
return this.expressionCompilationContextFactory;
}
@Override
public GroovyAnnotationMetadataBuilder getAnnotationMetadataBuilder() {
return annotationMetadataBuilder;
}
@Override
public void info(String message, @Nullable Element element) {
StringBuilder msg = new StringBuilder("Note: ").append(message);
if (element instanceof AbstractGroovyElement abstractGroovyElement) {
ASTNode expr = abstractGroovyElement.getNativeType().annotatedNode();
final String sample = sourceUnit.getSample(expr.getLineNumber(), expr.getColumnNumber(), new Janitor());
msg.append("\n\n").append(sample);
}
System.out.println(msg);
}
@Override
public void info(String message) {
System.out.println("Note: " + message);
}
@Override
public void fail(String message, @Nullable Element element) {
if (element instanceof AbstractGroovyElement abstractGroovyElement) {
AstMessageUtils.error(sourceUnit, abstractGroovyElement.getNativeType().annotatedNode(), message);
} else {
AstMessageUtils.error(sourceUnit, null, message);
}
}
public final void fail(String message, ASTNode expr) {
AstMessageUtils.error(sourceUnit, expr, message);
}
@Override
public void warn(String message, @Nullable Element element) {
if (element instanceof AbstractGroovyElement abstractGroovyElement) {
AstMessageUtils.warning(sourceUnit, abstractGroovyElement.getNativeType().annotatedNode(), message);
} else {
AstMessageUtils.warning(sourceUnit, null, message);
}
}
@Override
public OutputStream visitClass(String classname, @Nullable Element originatingElement) throws IOException {
return outputVisitor.visitClass(classname, originatingElement);
}
@Override
public OutputStream visitClass(String classname, Element... originatingElements) throws IOException {
return outputVisitor.visitClass(classname, originatingElements);
}
@Override
public void visitServiceDescriptor(String type, String classname) {
outputVisitor.visitServiceDescriptor(type, classname);
}
@Override
public void visitServiceDescriptor(String type, String classname, Element originatingElement) {
outputVisitor.visitServiceDescriptor(type, classname, originatingElement);
}
@Override
public Optional visitMetaInfFile(String path, Element... originatingElements) {
return outputVisitor.visitMetaInfFile(path, originatingElements);
}
@Override
public Optional visitGeneratedFile(String path) {
return outputVisitor.visitGeneratedFile(path);
}
@Override
public Optional visitGeneratedFile(String path, Element... originatingElements) {
return outputVisitor.visitGeneratedFile(path, originatingElements);
}
@Override
public Optional visitGeneratedSourceFile(String packageName, String fileNameWithoutExtension, Element... originatingElements) {
return outputVisitor.visitGeneratedSourceFile(packageName, fileNameWithoutExtension, originatingElements);
}
@Override
public void finish() {
outputVisitor.finish();
}
/**
* @return The source unit
*/
SourceUnit getSourceUnit() {
return sourceUnit;
}
/**
* @return The compilation unit
*/
@Internal
public CompilationUnit getCompilationUnit() {
return compilationUnit;
}
/**
* @return The native element helper
*/
@Internal
public GroovyNativeElementHelper getNativeElementHelper() {
return nativeElementHelper;
}
/**
* Groovy options source are {@link System#getProperties()} based.
* All properties MUST start with {@link GroovyVisitorContext#MICRONAUT_BASE_OPTION_NAME}
* @return options {@link Map}
*/
@Override
public Map getOptions() {
return VisitorContextUtils.getSystemOptions();
}
@Override
public MutableConvertibleValues put(CharSequence key, @Nullable Object value) {
return attributes.put(key, value);
}
@Override
public MutableConvertibleValues remove(CharSequence key) {
return attributes.remove(key);
}
@Override
public MutableConvertibleValues clear() {
return attributes.clear();
}
@Override
public Set names() {
return attributes.names();
}
@Override
public Collection values() {
return attributes.values();
}
@Override
public Optional get(CharSequence name, ArgumentConversionContext conversionContext) {
return attributes.get(name, conversionContext);
}
@Override
public Collection getGeneratedResources() {
return Collections.unmodifiableCollection(generatedResources);
}
@Override
public void addGeneratedResource(@NonNull String resource) {
generatedResources.add(resource);
}
/**
* @return Gets the produced bean definition builders.
*/
@Internal
public List getBeanElementBuilders() {
final ArrayList current = new ArrayList<>(beanDefinitionBuilders);
beanDefinitionBuilders.clear();
return current;
}
/**
* Adds a java bean definition builder.
* @param groovyBeanDefinitionBuilder The groovy bean definition builder
*/
@Internal
void addBeanDefinitionBuilder(GroovyBeanDefinitionBuilder groovyBeanDefinitionBuilder) {
this.beanDefinitionBuilders.add(groovyBeanDefinitionBuilder);
}
}