Skip to content

Commit

Permalink
feat:Qute: Cannot locate hyphenated template name
Browse files Browse the repository at this point in the history
Fixes redhat-developer#975

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Jul 13, 2024
1 parent cf93107 commit 4ffe2b9
Show file tree
Hide file tree
Showing 8 changed files with 388 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class QuteJavaConstants {
public static final String TEMPLATE_CLASS = "io.quarkus.qute.Template";

public static final String TEMPLATE_INSTANCE_INTERFACE = "io.quarkus.qute.TemplateInstance";

public static final String ENGINE_BUILDER_CLASS = "io.quarkus.qute.EngineBuilder";

public static final String VALUE_ANNOTATION_NAME = "value";
Expand All @@ -50,6 +50,9 @@ public class QuteJavaConstants {

public static final String CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS = "ignoreFragments";
public static final String CHECKED_TEMPLATE_ANNOTATION_BASE_PATH = "basePath";
public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME = "defaultName";
public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_HYPHENATED_ELEMENT_NAME = "<<hyphenated element name>>";
public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_UNDERSCORED_ELEMENT_NAME = "<<underscored element name>>";

// @TemplateExtension

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_BASE_PATH;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_HYPHENATED_ELEMENT_NAME;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_UNDERSCORED_ELEMENT_NAME;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.TEMPLATE_CLASS;
Expand Down Expand Up @@ -51,6 +54,7 @@
import com.redhat.qute.jdt.utils.IJDTUtils;
import com.redhat.qute.jdt.utils.JDTQuteProjectUtils;
import com.redhat.qute.jdt.utils.JDTTypeUtils;
import com.redhat.qute.jdt.utils.TemplateNameStrategy;
import com.redhat.qute.jdt.utils.TemplatePathInfo;

/**
Expand Down Expand Up @@ -138,7 +142,9 @@ public boolean visit(FieldDeclaration node) {
.getLocationExpressionFromConstructorParameter(variable.getName().getIdentifier());
}
String fieldName = variable.getName().getIdentifier();
collectTemplateLink(null, node, locationExpression, getTypeDeclaration(node), null, fieldName, false);
TemplateNameStrategy templateNameStrategy = TemplateNameStrategy.ELEMENT_NAME;
collectTemplateLink(null, node, locationExpression, getTypeDeclaration(node), null, fieldName, false,
templateNameStrategy);
}
}
return super.visit(node);
Expand Down Expand Up @@ -186,10 +192,12 @@ public boolean visit(TypeDeclaration node) {
// public static native TemplateInstance book(Book book);
boolean ignoreFragments = isIgnoreFragments(annotation);
String basePath = getBasePath(annotation);
TemplateNameStrategy templateNameStrategy = getDefaultName(annotation);
List body = node.bodyDeclarations();
for (Object declaration : body) {
if (declaration instanceof MethodDeclaration) {
collectTemplateLink(basePath, (MethodDeclaration) declaration, node, ignoreFragments);
collectTemplateLink(basePath, (MethodDeclaration) declaration, node, ignoreFragments,
templateNameStrategy);
}
}
}
Expand All @@ -208,8 +216,9 @@ public boolean visit(TypeDeclaration node) {
@Override
public boolean visit(RecordDeclaration node) {
if (isImplementTemplateInstance(node)) {
TemplateNameStrategy templateNameStrategy = TemplateNameStrategy.ELEMENT_NAME;
String recordName = node.getName().getIdentifier();
collectTemplateLink(null, node, null, node, null, recordName, false);
collectTemplateLink(null, node, null, node, null, recordName, false, templateNameStrategy);
}
return super.visit(node);
}
Expand Down Expand Up @@ -275,18 +284,52 @@ private static boolean isIgnoreFragments(Annotation checkedTemplateAnnotation) {
* @return the <code>basePath</code> value declared in the @CheckedTemplate
* annotation
*/
public static String getBasePath(Annotation checkedTemplateAnnotation) {
private static String getBasePath(Annotation checkedTemplateAnnotation) {
String basePath = null;
try {
Expression ignoreFragmentExpr = AnnotationUtils.getAnnotationMemberValueExpression(
checkedTemplateAnnotation, CHECKED_TEMPLATE_ANNOTATION_BASE_PATH);
basePath = AnnotationUtils.getString(ignoreFragmentExpr);
Expression basePathExpr = AnnotationUtils.getAnnotationMemberValueExpression(checkedTemplateAnnotation,
CHECKED_TEMPLATE_ANNOTATION_BASE_PATH);
basePath = AnnotationUtils.getString(basePathExpr);
} catch (Exception e) {
// Do nothing
}
return basePath;
}

/**
* Returns the <code>defaultName</code> value declared in the @CheckedTemplate
* annotation, relative to the templates root, to search the templates from.
* <code>
* @CheckedTemplate([email protected]_ELEMENT_NAME)
*</code>
*
* @param checkedTemplateAnnotation the CheckedTemplate annotation.
* @return the <code>defaultName</code> value declared in the @CheckedTemplate
* annotation
*/
private static TemplateNameStrategy getDefaultName(Annotation checkedTemplateAnnotation) {
TemplateNameStrategy defaultName = TemplateNameStrategy.ELEMENT_NAME;
try {
Expression defaultNameExpr = AnnotationUtils.getAnnotationMemberValueExpression(checkedTemplateAnnotation,
CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME);
defaultName = getDefaultName(AnnotationUtils.getString(defaultNameExpr));
} catch (Exception e) {
// Do nothing
}
return defaultName;
}

private static TemplateNameStrategy getDefaultName(String defaultName) {
switch (defaultName) {
case CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_HYPHENATED_ELEMENT_NAME:
return TemplateNameStrategy.HYPHENATED_ELEMENT_NAME;

case CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_UNDERSCORED_ELEMENT_NAME:
return TemplateNameStrategy.UNDERSCORED_ELEMENT_NAME;
}
return TemplateNameStrategy.ELEMENT_NAME;
}

@Override
public void endVisit(TypeDeclaration node) {
levelTypeDecl--;
Expand All @@ -302,24 +345,28 @@ private static TypeDeclaration getTypeDeclaration(ASTNode node) {
}

private void collectTemplateLink(String basePath, MethodDeclaration methodDeclaration, TypeDeclaration type,
boolean ignoreFragment) {
boolean ignoreFragment, TemplateNameStrategy templateNameStrategy) {
String className = null;
boolean innerClass = levelTypeDecl > 1;
if (innerClass) {
className = JDTTypeUtils.getSimpleClassName(typeRoot.getElementName());
}
String methodName = methodDeclaration.getName().getIdentifier();
collectTemplateLink(basePath, methodDeclaration, null, type, className, methodName, ignoreFragment);
collectTemplateLink(basePath, methodDeclaration, null, type, className, methodName, ignoreFragment,
templateNameStrategy);
}

private void collectTemplateLink(String basePath, ASTNode fieldOrMethod, StringLiteral locationAnnotation,
AbstractTypeDeclaration type, String className, String fieldOrMethodName, boolean ignoreFragment) {
AbstractTypeDeclaration type, String className, String fieldOrMethodName, boolean ignoreFragment,
TemplateNameStrategy templateNameStrategy) {
try {
String location = locationAnnotation != null ? locationAnnotation.getLiteralValue() : null;
IProject project = typeRoot.getJavaProject().getProject();
TemplatePathInfo templatePathInfo = location != null
? JDTQuteProjectUtils.getTemplatePath(basePath, null, location, ignoreFragment)
: JDTQuteProjectUtils.getTemplatePath(basePath, className, fieldOrMethodName, ignoreFragment);
? JDTQuteProjectUtils.getTemplatePath(basePath, null, location, ignoreFragment,
templateNameStrategy)
: JDTQuteProjectUtils.getTemplatePath(basePath, className, fieldOrMethodName, ignoreFragment,
templateNameStrategy);
IFile templateFile = null;
if (location == null) {
templateFile = getTemplateFile(project, templatePathInfo.getTemplateUri());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_BASE_PATH;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS;
import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION;
import static com.redhat.qute.jdt.utils.JDTQuteProjectUtils.getTemplatePath;
Expand Down Expand Up @@ -43,6 +44,7 @@
import com.redhat.qute.jdt.template.datamodel.SearchContext;
import com.redhat.qute.jdt.utils.AnnotationUtils;
import com.redhat.qute.jdt.utils.JDTTypeUtils;
import com.redhat.qute.jdt.utils.TemplateNameStrategy;
import com.redhat.qute.jdt.utils.TemplatePathInfo;

/**
Expand Down Expand Up @@ -91,8 +93,9 @@ protected void processAnnotation(IJavaElement javaElement, IAnnotation checkedTe
IType type = (IType) javaElement;
boolean ignoreFragments = isIgnoreFragments(checkedTemplateAnnotation);
String basePath = getBasePath(checkedTemplateAnnotation);
collectDataModelTemplateForCheckedTemplate(type, basePath, ignoreFragments, context.getTypeResolver(type),
context.getDataModelProject().getTemplates(), monitor);
TemplateNameStrategy templateNameStrategy = getDefaultName(checkedTemplateAnnotation);
collectDataModelTemplateForCheckedTemplate(type, basePath, ignoreFragments, templateNameStrategy,
context.getTypeResolver(type), context.getDataModelProject().getTemplates(), monitor);
}
}

Expand Down Expand Up @@ -145,6 +148,32 @@ private static String getBasePath(IAnnotation checkedTemplateAnnotation) {
return basePath;
}

/**
* Returns the <code>defaultName</code> value declared in the @CheckedTemplate
* annotation, relative to the templates root, to search the templates from.
* <code>
* @CheckedTemplate([email protected]_ELEMENT_NAME)
*</code>
*
* @param checkedTemplateAnnotation the CheckedTemplate annotation.
* @return the <code>defaultName</code> value declared in the @CheckedTemplate
* annotation
*/
private static TemplateNameStrategy getDefaultName(IAnnotation checkedTemplateAnnotation) {
TemplateNameStrategy defaultName = TemplateNameStrategy.ELEMENT_NAME;
try {
for (IMemberValuePair pair : checkedTemplateAnnotation.getMemberValuePairs()) {
if (CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME.equalsIgnoreCase(pair.getMemberName())) {
String value = AnnotationUtils.getValueAsString(pair);
System.err.println(value);
}
}
} catch (Exception e) {
// Do nothing
}
return defaultName;
}

/**
* Collect data model template from @CheckedTemplate.
*
Expand All @@ -158,8 +187,8 @@ private static String getBasePath(IAnnotation checkedTemplateAnnotation) {
* @throws JavaModelException
*/
private static void collectDataModelTemplateForCheckedTemplate(IType type, String basePath, boolean ignoreFragments,
ITypeResolver typeResolver, List<DataModelTemplate<DataModelParameter>> templates, IProgressMonitor monitor)
throws JavaModelException {
TemplateNameStrategy templateNameStrategy, ITypeResolver typeResolver,
List<DataModelTemplate<DataModelParameter>> templates, IProgressMonitor monitor) throws JavaModelException {
boolean innerClass = type.getParent() != null && type.getParent().getElementType() == IJavaElement.TYPE;
String className = !innerClass ? null
: JDTTypeUtils.getSimpleClassName(
Expand All @@ -172,7 +201,8 @@ private static void collectDataModelTemplateForCheckedTemplate(IType type, Strin
for (IMethod method : methods) {

// src/main/resources/templates/${className}/${methodName}.qute.html
TemplatePathInfo templatePathInfo = getTemplatePath(basePath, className, method.getElementName(), ignoreFragments);
TemplatePathInfo templatePathInfo = getTemplatePath(basePath, className, method.getElementName(),
ignoreFragments, templateNameStrategy);

// Get or create template
String templateUri = templatePathInfo.getTemplateUri();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.redhat.qute.jdt.template.datamodel.AbstractFieldDeclarationTypeReferenceDataModelProvider;
import com.redhat.qute.jdt.template.datamodel.SearchContext;
import com.redhat.qute.jdt.utils.AnnotationUtils;
import com.redhat.qute.jdt.utils.TemplateNameStrategy;

/**
* Template field support.
Expand Down Expand Up @@ -123,7 +124,9 @@ private static DataModelTemplate<DataModelParameter> createTemplateDataModel(IFi
: getLocation(field);
String fieldName = field.getElementName();
// src/main/resources/templates/${methodName}.qute.html
String templateUri = getTemplatePath(null, null, location != null ? location : fieldName, true).getTemplateUri();
TemplateNameStrategy templateNameStrategy = TemplateNameStrategy.ELEMENT_NAME;
String templateUri = getTemplatePath(null, null, location != null ? location : fieldName, true,
templateNameStrategy).getTemplateUri();

// Create template data model with:
// - template uri : Qute template file which must be bind with data model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.redhat.qute.jdt.internal.template.TemplateDataSupport;
import com.redhat.qute.jdt.template.datamodel.AbstractInterfaceImplementationDataModelProvider;
import com.redhat.qute.jdt.template.datamodel.SearchContext;
import com.redhat.qute.jdt.utils.TemplateNameStrategy;

/**
* Template Records support for template files:
Expand Down Expand Up @@ -83,7 +84,8 @@ private static DataModelTemplate<DataModelParameter> createTemplateDataModel(ITy

String recordName = type.getElementName();
// src/main/resources/templates/${recordName}.qute.html
String templateUri = getTemplatePath(null, null, recordName, true).getTemplateUri();
TemplateNameStrategy templateNameStrategy = TemplateNameStrategy.ELEMENT_NAME;
String templateUri = getTemplatePath(null, null, recordName, true, templateNameStrategy).getTemplateUri();

// Create template data model with:
// - template uri : Qute template file which must be bind with data model.
Expand All @@ -98,7 +100,8 @@ private static DataModelTemplate<DataModelParameter> createTemplateDataModel(ITy
for (IField field : type.getRecordComponents()) {
DataModelParameter parameter = new DataModelParameter();
parameter.setKey(field.getElementName());
parameter.setSourceType(typeResolver.resolveTypeSignature(field.getTypeSignature(), field.getDeclaringType()));
parameter.setSourceType(
typeResolver.resolveTypeSignature(field.getTypeSignature(), field.getDeclaringType()));
template.getParameters().add(parameter);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -29,6 +30,8 @@
import com.redhat.qute.commons.ProjectInfo;
import com.redhat.qute.jdt.internal.QuteJavaConstants;

import io.quarkus.runtime.util.StringUtil;

/**
* JDT Qute utilities.
*
Expand Down Expand Up @@ -87,7 +90,7 @@ public static String getProjectUri(IJavaProject project) {
* @return the project URI of the given project.
*/
public static String getProjectURI(IProject project) {
return project.getName(); // .getLocation().toOSString();
return project.getName();
}

/**
Expand All @@ -112,7 +115,7 @@ public static boolean hasQuteSupport(IJavaProject javaProject) {
}

public static TemplatePathInfo getTemplatePath(String basePath, String className, String methodOrFieldName,
boolean ignoreFragments) {
boolean ignoreFragments, TemplateNameStrategy templateNameStrategy) {
String fragmentId = null;
StringBuilder templateUri = new StringBuilder(TEMPLATES_BASE_DIR);
if (basePath != null && !DEFAULTED.equals(basePath)) {
Expand All @@ -127,10 +130,38 @@ public static TemplatePathInfo getTemplatePath(String basePath, String className
methodOrFieldName = methodOrFieldName.substring(0, fragmentIndex);
}
}
templateUri.append(methodOrFieldName);
templateUri.append(defaultedName(templateNameStrategy, methodOrFieldName));
return new TemplatePathInfo(templateUri.toString(), fragmentId);
}

/**
*
* @param defaultNameStrategy
* @param value
* @return
* @see <a href=
* "https://github.com/quarkusio/quarkus/blob/32392afcd5cbbed86fe119ed90d4c679d4d52123/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java#L562C5-L578C6">QuteProcessor#defaultName</a>
*/
private static String defaultedName(TemplateNameStrategy defaultNameStrategy, String value) {
switch (defaultNameStrategy) {
case ELEMENT_NAME:
return value;
case HYPHENATED_ELEMENT_NAME:
return StringUtil.hyphenate(value);
case UNDERSCORED_ELEMENT_NAME:
return String.join("_", new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return StringUtil.lowerCase(StringUtil.camelHumpsIterator(value));
}
});
default:
return value;
// throw new IllegalArgumentException("Unsupported
// @CheckedTemplate#defaultName() value: " + defaultNameStrategy);
}
}

/**
* Appends a segment to a path, add trailing "/" if necessary
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.redhat.qute.jdt.utils;

public enum TemplateNameStrategy {

ELEMENT_NAME,
HYPHENATED_ELEMENT_NAME,
UNDERSCORED_ELEMENT_NAME,
OTHER
}
Loading

0 comments on commit 4ffe2b9

Please sign in to comment.