-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for @TemplateGlobal annotation
Signed-off-by: Alexander Chen <alchen@redhat.com>
- Loading branch information
Alexander Chen
committed
May 26, 2022
1 parent
b127161
commit 9259402
Showing
3 changed files
with
211 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
203 changes: 203 additions & 0 deletions
203
...java/com/redhat/qute/jdt/internal/template/datamodel/TemplateGlobalAnnotationSupport.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
* @TemplateGlobal | ||
* public class Globals { | ||
* | ||
* static int age = 40; | ||
* | ||
* static Color[] myColors() { | ||
* return new Color[] { Color.RED, Color.BLUE }; | ||
* } | ||
* | ||
* @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; | ||
} | ||
|
||
} |