Skip to content

Commit

Permalink
Added support for @TemplateGlobal annotation
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Chen <alchen@redhat.com>
  • Loading branch information
Alexander Chen committed May 26, 2022
1 parent b127161 commit 9259402
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 1 deletion.
1 change: 1 addition & 0 deletions qute.jdt/com.redhat.qute.jdt/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<provider class="com.redhat.qute.jdt.internal.template.datamodel.TemplateFieldSupport" />
<provider class="com.redhat.qute.jdt.internal.template.datamodel.TemplateDataAnnotationSupport" />
<provider class="com.redhat.qute.jdt.internal.template.datamodel.TemplateEnumAnnotationSupport" />
<provider class="com.redhat.qute.jdt.internal.template.datamodel.TemplateGlobalAnnotationSupport" />
</extension>

<!-- Data model providers for Quarkus integration for Qute -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ public class QuteJavaConstants {
public static final String TEMPLATE_DATA_ANNOTATION_IGNORE_SUPER_CLASSES = "ignoreSuperclasses";

public static final String TEMPLATE_DATA_ANNOTATION_NAMESPACE = "namespace";

// @TemplateEnum

public static final String TEMPLATE_ENUM_ANNOTATION = "io.quarkus.qute.TemplateEnum";

// @TemplateGlobal

public static final String TEMPLATE_GLOBAL_ANNOTATION = "io.quarkus.qute.TemplateGlobal";

public static final String TEMPLATE_GLOBAL_ANNOTATION_NAME = "name";

// @io.quarkus.runtime.annotations.RegisterForReflection

public static final String REGISTER_FOR_REFLECTION_ANNOTATION = "io.quarkus.runtime.annotations.RegisterForReflection";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*******************************************************************************
* Copyright (c) 2022 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0git che
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.qute.jdt.internal.template.datamodel;

import static com.redhat.qute.jdt.internal.QuteJavaConstants.TEMPLATE_GLOBAL_ANNOTATION;

import java.lang.reflect.Modifier;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

import com.redhat.qute.commons.datamodel.resolvers.ValueResolverInfo;
import com.redhat.qute.jdt.QuteSupportForTemplate;
import com.redhat.qute.jdt.internal.resolver.ITypeResolver;
import com.redhat.qute.jdt.template.datamodel.AbstractAnnotationTypeReferenceDataModelProvider;
import com.redhat.qute.jdt.template.datamodel.SearchContext;
import com.redhat.qute.jdt.utils.AnnotationUtils;

/**
* @TemplateGlobal annotation support.
*
* <code>
* &#64;TemplateGlobal
* public class Globals {
*
* static int age = 40;
*
* static Color[] myColors() {
* return new Color[] { Color.RED, Color.BLUE };
* }
*
* &#64;TemplateGlobal(name = "currentUser")
* static String user() {
* return "Mia";
* }
* }
* </code>
*
*
* @see https://quarkus.io/guides/qute-reference#global_variables
*
*/
public class TemplateGlobalAnnotationSupport extends AbstractAnnotationTypeReferenceDataModelProvider {

private static final Logger LOGGER = Logger.getLogger(TemplateGlobalAnnotationSupport.class.getName());

private static final String[] ANNOTATION_NAMES = {
TEMPLATE_GLOBAL_ANNOTATION
};

@Override
protected String[] getAnnotationNames() {
return ANNOTATION_NAMES;
}

@Override
protected void processAnnotation(IJavaElement javaElement, IAnnotation annotation, String annotationName,
SearchContext context, IProgressMonitor monitor) throws JavaModelException {
if (!(javaElement instanceof IAnnotatable)) {
return;
}
IAnnotation templateGlobal = AnnotationUtils.getAnnotation((IAnnotatable) javaElement,
TEMPLATE_GLOBAL_ANNOTATION);
if (templateGlobal == null) {
return;
}
if (javaElement.getElementType() == IJavaElement.TYPE) {
IType type = (IType) javaElement;
collectResolversForTemplateGlobal(type, templateGlobal, context.getDataModelProject().getValueResolvers(),
monitor);
} else {
ITypeResolver typeResolver = QuteSupportForTemplate.createTypeResolver((IType) javaElement);
if (javaElement.getElementType() == IJavaElement.FIELD
|| javaElement.getElementType() == IJavaElement.METHOD) {
IMember member = (IMember) javaElement;
collectResolversForTemplateGlobal(member, templateGlobal,
context.getDataModelProject().getValueResolvers(), typeResolver, monitor);
}
}
}

private void collectResolversForTemplateGlobal(IType type, IAnnotation templateGlobal,
List<ValueResolverInfo> resolvers, IProgressMonitor monitor) {
try {
ITypeResolver typeResolver = QuteSupportForTemplate.createTypeResolver(type);
IField[] fields = type.getFields();
for (IField field : fields) {
if (isTemplateGlobalMember(field)) {
collectResolversForTemplateGlobal(field, templateGlobal, resolvers, typeResolver, monitor);
}
}
IMethod[] methods = type.getMethods();
for (IMethod method : methods) {
if (isTemplateGlobalMember(method)) {
collectResolversForTemplateGlobal(method, templateGlobal, resolvers, typeResolver, monitor);
}
}
} catch (JavaModelException e) {
LOGGER.log(Level.SEVERE, "Error while getting methods of '" + type.getElementName() + "'.", e);
}
}

private void collectResolversForTemplateGlobal(IMember member, IAnnotation templateGlobal,
List<ValueResolverInfo> resolvers, ITypeResolver typeResolver, IProgressMonitor monitor) {
// every non-void non-private static method that declares no parameters and
// every non-private static field is considered a global variable
if (isTemplateGlobalMember(member)) {
String sourceType = member.getDeclaringType().getFullyQualifiedName();
ValueResolverInfo resolver = new ValueResolverInfo();
resolver.setSourceType(sourceType);
resolver.setSignature(getSignature(member, typeResolver));
try {
resolver.setNamed(AnnotationUtils.getAnnotationMemberValue(templateGlobal, "value"));
} catch (JavaModelException e) {
LOGGER.log(Level.SEVERE, "Error while getting annotation member value of 'named'.", e);
}
resolver.setGlobalVariable(true);
if (!resolvers.contains(resolver)) {
resolvers.add(resolver);
}
}
}

/**
* Returns true if the given member is supported by @TemplateGlobal and false
* otherwise.
*
* A global variable method:
*
* <ul>
* <li>must not be private</li>
* <li>must be static,</li>
* <li>must not accept any parameter,</li>
* <li>must not return {@code void},</li>
* </ul>
*
* A global variable field:
*
* <ul>
* <li>must not be private</li>
* <li>must be static,</li>
* </ul>
*
* @param member the member to check.
* @return true if the given member <code>member</code> is a template global
* member and false otherwise.
*/
private static boolean isTemplateGlobalMember(IMember member) {
try {
// every non-void non-private static method that declares no parameters and
// every non-private static field is considered a global variable
if (!Modifier.isPrivate(member.getFlags()) && Modifier.isStatic(member.getFlags())) {
if (member.getElementType() == IJavaElement.FIELD) {
return true;
} else if (member.getElementType() == IJavaElement.METHOD) {
IMethod method = (IMethod) member;
return method.getParameters().length == 0 && !"void".equals(method.getReturnType());
}
}
return false;
} catch (JavaModelException e) {
LOGGER.log(Level.SEVERE, "Error while getting method information of '" + member.getElementName() + "'.", e);
return false;
}
}

/**
* Assign the signature based on the IMember type
*
* @param javaMember Java member to return signature for
* @param typeResolver type resolver to declare signature
* @return the Java member type signature
*/
private static String getSignature(IMember javaMember, ITypeResolver typeResolver) {
switch (javaMember.getElementType()) {
case IJavaElement.FIELD:
return typeResolver.resolveFieldSignature((IField) javaMember);
case IJavaElement.METHOD:
return typeResolver.resolveMethodSignature((IMethod) javaMember);
}
return null;
}

}

0 comments on commit 9259402

Please sign in to comment.