mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
Merge pull request #6444 from mkouba/issue-6438
Qute - support @TemplateExtension declared on a class
This commit is contained in:
@@ -538,10 +538,25 @@ NOTE: A value resolver is also generated for all types used in parameter declara
|
||||
[[template_extension_methods]]
|
||||
=== Template Extension Methods
|
||||
|
||||
A value resolver is automatically generated for a template extension method annotated with `@TemplateExtension`.
|
||||
The method must be static, must not return `void` and must accept at least one parameter.
|
||||
The class of the first parameter is used to match the base object and the method name is used to match the property name.
|
||||
Extension methods can be used to extend the data classes with new functionality.
|
||||
For example, it is possible to add "computed properties" and "virtual methods".
|
||||
A value resolver is automatically generated for a method annotated with `@TemplateExtension`.
|
||||
If declared on a class a value resolver is generated for every non-private method declared on the class.
|
||||
Methods that do not meet the following requirements are ignored.
|
||||
|
||||
A template extension method:
|
||||
|
||||
* must be static,
|
||||
* must not return `void`,
|
||||
* must accept at least one parameter.
|
||||
|
||||
The class of the first parameter is always used to match the base object.
|
||||
The method name is used to match the property name by default.
|
||||
However, it is possible to specify the matching name with `TemplateExtension#matchName()`.
|
||||
|
||||
NOTE: A special constant - `ANY` - may be used to specify that the extension method matches any name. In that case, the method must declare at least two parameters and the second parameter must be a string.
|
||||
|
||||
.Extension Method Example
|
||||
[source,java]
|
||||
----
|
||||
package org.acme;
|
||||
@@ -555,25 +570,48 @@ class Item {
|
||||
}
|
||||
}
|
||||
|
||||
@TemplateExtension
|
||||
class MyExtensions {
|
||||
|
||||
@TemplateExtension
|
||||
static BigDecimal discountedPrice(Item item) { <1>
|
||||
return item.getPrice().multiply(new BigDecimal("0.9"));
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> The method matches `Item.class` and `discountedPrice` property name.
|
||||
<1> This method matches an expression with base object of the type `Item.class` and the `discountedPrice` property name.
|
||||
|
||||
This template extension method makes it possible to render the following template:
|
||||
|
||||
[source,html]
|
||||
----
|
||||
{#each items} <1>
|
||||
{it.discountedPrice}
|
||||
{/each}
|
||||
{item.discountedPrice} <1>
|
||||
----
|
||||
<1> `items` is resolved to a list of `org.acme.Item` instances.
|
||||
<1> `item` is resolved to an instance of `org.acme.Item`.
|
||||
|
||||
==== Method Parameters
|
||||
|
||||
An extension method may accept multiple parameters.
|
||||
The first parameter is always used to pass the base object, ie. `org.acme.Item` in the previous example.
|
||||
Other parameters are resolved when rendering the template and passed to the extension method.
|
||||
|
||||
.Multiple Parameters Example
|
||||
[source,java]
|
||||
----
|
||||
@TemplateExtension
|
||||
class MyExtensions {
|
||||
|
||||
static BigDecimal scale(BigDecimal val, int scale, RoundingMode mode) { <1>
|
||||
return val.setScale(scale, mode);
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> This method matches an expression with base object of the type `BigDecimal.class`, with the `scale` virtual method name and two virtual method parameters.
|
||||
|
||||
[source,html]
|
||||
----
|
||||
{item.discountedPrice.scale(2,mode)} <1>
|
||||
----
|
||||
<1> `item.discountedPrice` is resolved to an instance of `BigDecimal`.
|
||||
|
||||
=== @TemplateData
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ public class QuteProcessor {
|
||||
static final DotName MAP = DotName.createSimple(Map.class.getName());
|
||||
static final DotName MAP_ENTRY = DotName.createSimple(Entry.class.getName());
|
||||
|
||||
private static final String MATCH_NAME = "matchName";
|
||||
|
||||
@BuildStep
|
||||
FeatureBuildItem feature() {
|
||||
return new FeatureBuildItem(FeatureBuildItem.QUTE);
|
||||
@@ -255,23 +257,51 @@ public class QuteProcessor {
|
||||
BuildProducer<TemplateExtensionMethodBuildItem> extensionMethods) {
|
||||
|
||||
IndexView index = beanArchiveIndex.getIndex();
|
||||
Map<MethodInfo, AnnotationInstance> methods = new HashMap<>();
|
||||
Map<ClassInfo, AnnotationInstance> classes = new HashMap<>();
|
||||
|
||||
for (AnnotationInstance templateExtension : index.getAnnotations(ExtensionMethodGenerator.TEMPLATE_EXTENSION)) {
|
||||
if (templateExtension.target().kind() == Kind.METHOD) {
|
||||
MethodInfo method = templateExtension.target().asMethod();
|
||||
ExtensionMethodGenerator.validate(method);
|
||||
String matchName = null;
|
||||
AnnotationValue matchNameValue = templateExtension.value("matchName");
|
||||
if (matchNameValue != null) {
|
||||
matchName = matchNameValue.asString();
|
||||
}
|
||||
if (matchName == null) {
|
||||
matchName = method.name();
|
||||
}
|
||||
extensionMethods.produce(new TemplateExtensionMethodBuildItem(method, matchName,
|
||||
index.getClassByName(method.parameters().get(0).name())));
|
||||
methods.put(templateExtension.target().asMethod(), templateExtension);
|
||||
} else if (templateExtension.target().kind() == Kind.CLASS) {
|
||||
classes.put(templateExtension.target().asClass(), templateExtension);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<MethodInfo, AnnotationInstance> entry : methods.entrySet()) {
|
||||
MethodInfo method = entry.getKey();
|
||||
ExtensionMethodGenerator.validate(method);
|
||||
produceExtensionMethod(index, extensionMethods, method, entry.getValue());
|
||||
LOGGER.debugf("Found template extension method %s declared on %s", method,
|
||||
method.declaringClass().name());
|
||||
}
|
||||
|
||||
for (Entry<ClassInfo, AnnotationInstance> entry : classes.entrySet()) {
|
||||
ClassInfo clazz = entry.getKey();
|
||||
for (MethodInfo method : clazz.methods()) {
|
||||
if (!Modifier.isStatic(method.flags()) || method.returnType().kind() == org.jboss.jandex.Type.Kind.VOID
|
||||
|| method.parameters().isEmpty() || Modifier.isPrivate(method.flags()) || methods.containsKey(method)) {
|
||||
continue;
|
||||
}
|
||||
produceExtensionMethod(index, extensionMethods, method, entry.getValue());
|
||||
LOGGER.debugf("Found template extension method %s declared on %s", method,
|
||||
method.declaringClass().name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void produceExtensionMethod(IndexView index, BuildProducer<TemplateExtensionMethodBuildItem> extensionMethods,
|
||||
MethodInfo method, AnnotationInstance extensionAnnotation) {
|
||||
String matchName = null;
|
||||
AnnotationValue matchNameValue = extensionAnnotation.value(MATCH_NAME);
|
||||
if (matchNameValue != null) {
|
||||
matchName = matchNameValue.asString();
|
||||
}
|
||||
if (matchName == null) {
|
||||
matchName = method.name();
|
||||
}
|
||||
extensionMethods.produce(new TemplateExtensionMethodBuildItem(method, matchName,
|
||||
index.getClassByName(method.parameters().get(0).name())));
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
@@ -411,6 +441,9 @@ public class QuteProcessor {
|
||||
idx = name.lastIndexOf(ValueResolverGenerator.SUFFIX);
|
||||
}
|
||||
String className = name.substring(0, idx).replace("/", ".");
|
||||
if (className.contains(ValueResolverGenerator.NESTED_SEPARATOR)) {
|
||||
className = className.replace(ValueResolverGenerator.NESTED_SEPARATOR, "$");
|
||||
}
|
||||
boolean appClass = appClassPredicate.test(className);
|
||||
LOGGER.debugf("Writing %s [appClass=%s]", name, appClass);
|
||||
generatedClass.produce(new GeneratedClassBuildItem(appClass, name, data));
|
||||
@@ -451,7 +484,7 @@ public class QuteProcessor {
|
||||
|
||||
ExtensionMethodGenerator extensionMethodGenerator = new ExtensionMethodGenerator(classOutput);
|
||||
for (TemplateExtensionMethodBuildItem templateExtension : templateExtensionMethods) {
|
||||
extensionMethodGenerator.generate(templateExtension.getMethod());
|
||||
extensionMethodGenerator.generate(templateExtension.getMethod(), templateExtension.getMatchName());
|
||||
}
|
||||
generatedTypes.addAll(extensionMethodGenerator.getGeneratedTypes());
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ public class ReflectionResolverTest {
|
||||
static final QuarkusUnitTest config = new QuarkusUnitTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
|
||||
.addClasses(HelloReflect.class)
|
||||
// Make sure we do not detect the template data
|
||||
.addAsResource(new StringAsset("quarkus.qute.detect-template-data=false"), "application.properties")
|
||||
.addAsResource(new StringAsset("{age}:{ping}:{noMatch}"), "templates/reflect.txt"));
|
||||
|
||||
@Inject
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package io.quarkus.qute.deployment;
|
||||
|
||||
import static io.quarkus.qute.TemplateExtension.ANY;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import io.quarkus.qute.Engine;
|
||||
import io.quarkus.qute.Template;
|
||||
import io.quarkus.qute.TemplateExtension;
|
||||
import io.quarkus.test.QuarkusUnitTest;
|
||||
|
||||
public class TemplateExtensionMethodsTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final QuarkusUnitTest config = new QuarkusUnitTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
|
||||
.addClasses(Foo.class, Extensions.class)
|
||||
.addAsResource(new StringAsset("{foo.name.toLower} {foo.name.ignored} {foo.callMe(1)} {foo.baz}"),
|
||||
"templates/foo.txt")
|
||||
.addAsResource(new StringAsset("{baz.setScale(2,roundingMode)}"),
|
||||
"templates/baz.txt")
|
||||
.addAsResource(new StringAsset("{anyInt.foo('bing')}"),
|
||||
"templates/any.txt"));
|
||||
|
||||
@Inject
|
||||
Template foo;
|
||||
|
||||
@Inject
|
||||
Engine engine;
|
||||
|
||||
@Test
|
||||
public void testTemplateExtensions() {
|
||||
assertEquals("fantomas NOT_FOUND 11 baz",
|
||||
foo.data("foo", new Foo("Fantomas", 10l)).render());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodParameters() {
|
||||
assertEquals("123.46",
|
||||
engine.getTemplate("baz.txt").data("roundingMode", RoundingMode.HALF_UP).data("baz", new BigDecimal("123.4563"))
|
||||
.render());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchAnyWithParameter() {
|
||||
assertEquals("10=bing",
|
||||
engine.getTemplate("any.txt").data("anyInt", 10).render());
|
||||
}
|
||||
|
||||
@TemplateExtension
|
||||
public static class Extensions {
|
||||
|
||||
String ignored(String val) {
|
||||
return val.toLowerCase();
|
||||
}
|
||||
|
||||
static String toLower(String val) {
|
||||
return val.toLowerCase();
|
||||
}
|
||||
|
||||
static Long callMe(Foo foo, Integer val) {
|
||||
return foo.age + val;
|
||||
}
|
||||
|
||||
@TemplateExtension(matchName = "baz")
|
||||
static String override(Foo foo) {
|
||||
return "baz";
|
||||
}
|
||||
|
||||
static BigDecimal setScale(BigDecimal val, int scale, RoundingMode mode) {
|
||||
return val.setScale(scale, mode);
|
||||
}
|
||||
|
||||
@TemplateExtension(matchName = ANY)
|
||||
static String any(Integer val, String name, String info) {
|
||||
return val + "=" + info;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,6 +85,7 @@ class EvaluatorImpl implements Evaluator {
|
||||
new EvalContextImpl(false, parent.getData(), evalContext.name, parent),
|
||||
this.resolvers.iterator());
|
||||
}
|
||||
LOGGER.tracef("Unable to resolve %s", evalContext);
|
||||
return Results.NOT_FOUND;
|
||||
}
|
||||
ValueResolver resolver = resolvers.next();
|
||||
@@ -148,6 +149,14 @@ class EvaluatorImpl implements Evaluator {
|
||||
return resolutionContext.evaluate(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("EvalContextImpl [tryParent=").append(tryParent).append(", base=").append(base).append(", name=")
|
||||
.append(name).append(", params=").append(params).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,12 +30,16 @@ public class ReflectionValueResolver implements ValueResolver {
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(EvalContext context) {
|
||||
return context.getBase() != null;
|
||||
Object base = context.getBase();
|
||||
if (base == null) {
|
||||
return false;
|
||||
}
|
||||
return memberCache.computeIfAbsent(MemberKey.newInstance(base, context.getName()), ReflectionValueResolver::findWrapper)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Object> resolve(EvalContext context) {
|
||||
|
||||
Object base = context.getBase();
|
||||
MemberKey key = MemberKey.newInstance(base, context.getName());
|
||||
MemberWrapper wrapper = memberCache.computeIfAbsent(key, ReflectionValueResolver::findWrapper).orElse(null);
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package io.quarkus.qute;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A value resolver is automatically generated for a template extension method.
|
||||
* A value resolver is automatically generated for a method annotated with this annotation. If declared on a class a value
|
||||
* resolver is generated for every non-private static method declared on the class. Methods that do not meet the following
|
||||
* requirements are ignored.
|
||||
* <p>
|
||||
* The method must be static, must not return {@code void} and must accept at least one parameter. The class of the first
|
||||
* parameter is used to match the base object.
|
||||
* A template extension method:
|
||||
* <ul>
|
||||
* <li>must be static,</li>
|
||||
* <li>must not return {@code void},</li>
|
||||
* <li>must accept at least one parameter.</li>
|
||||
* <p>
|
||||
* The class of the first parameter is used to match the base object.
|
||||
* <p>
|
||||
* By default, the method name is used to match the property name. However, it is possible to specify the matching name with
|
||||
* {@link #matchName()}. A special constant - {@link #ANY} - may be used to specify that the extension method matches any name.
|
||||
@@ -25,7 +33,7 @@ import java.lang.annotation.Target;
|
||||
* </pre>
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@Target(METHOD)
|
||||
@Target({ METHOD, TYPE })
|
||||
public @interface TemplateExtension {
|
||||
|
||||
static final String ANY = "*";
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@@ -32,6 +33,7 @@ import org.jboss.jandex.AnnotationValue;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
import org.jboss.jandex.Type;
|
||||
import org.jboss.jandex.Type.Kind;
|
||||
|
||||
public class ExtensionMethodGenerator {
|
||||
@@ -65,19 +67,21 @@ public class ExtensionMethodGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
public void generate(MethodInfo method) {
|
||||
public void generate(MethodInfo method, String matchName) {
|
||||
|
||||
// Validate the method first
|
||||
validate(method);
|
||||
|
||||
String matchName = null;
|
||||
AnnotationInstance extensionAnnotation = method.annotation(TEMPLATE_EXTENSION);
|
||||
if (extensionAnnotation != null) {
|
||||
AnnotationValue matchNameValue = extensionAnnotation.value("matchName");
|
||||
if (matchNameValue != null) {
|
||||
matchName = matchNameValue.asString();
|
||||
if (matchName == null) {
|
||||
AnnotationInstance extensionAnnotation = method.annotation(TEMPLATE_EXTENSION);
|
||||
if (extensionAnnotation != null) {
|
||||
AnnotationValue matchNameValue = extensionAnnotation.value("matchName");
|
||||
if (matchNameValue != null) {
|
||||
matchName = matchNameValue.asString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchName == null) {
|
||||
matchName = method.name();
|
||||
} else if (matchName.equals(TemplateExtension.ANY)) {
|
||||
@@ -92,7 +96,8 @@ public class ExtensionMethodGenerator {
|
||||
ClassInfo declaringClass = method.declaringClass();
|
||||
String baseName;
|
||||
if (declaringClass.enclosingClass() != null) {
|
||||
baseName = simpleName(declaringClass.enclosingClass()) + "_" + simpleName(declaringClass);
|
||||
baseName = simpleName(declaringClass.enclosingClass()) + ValueResolverGenerator.NESTED_SEPARATOR
|
||||
+ simpleName(declaringClass);
|
||||
} else {
|
||||
baseName = simpleName(declaringClass);
|
||||
}
|
||||
@@ -105,12 +110,19 @@ public class ExtensionMethodGenerator {
|
||||
ClassCreator valueResolver = ClassCreator.builder().classOutput(classOutput).className(generatedName)
|
||||
.interfaces(ValueResolver.class).build();
|
||||
|
||||
implementGetPriority(valueResolver);
|
||||
implementAppliesTo(valueResolver, method, matchName);
|
||||
implementResolve(valueResolver, declaringClass, method, matchName);
|
||||
|
||||
valueResolver.close();
|
||||
}
|
||||
|
||||
private void implementGetPriority(ClassCreator valueResolver) {
|
||||
MethodCreator getPriority = valueResolver.getMethodCreator("getPriority", int.class)
|
||||
.setModifiers(ACC_PUBLIC);
|
||||
getPriority.returnValue(getPriority.load(5));
|
||||
}
|
||||
|
||||
private void implementResolve(ClassCreator valueResolver, ClassInfo declaringClass, MethodInfo method, String matchName) {
|
||||
MethodCreator resolve = valueResolver.getMethodCreator("resolve", CompletionStage.class, EvalContext.class)
|
||||
.setModifiers(ACC_PUBLIC);
|
||||
@@ -135,12 +147,14 @@ public class ExtensionMethodGenerator {
|
||||
} else {
|
||||
ret = resolve
|
||||
.newInstance(MethodDescriptor.ofConstructor(CompletableFuture.class));
|
||||
int realParamSize = paramSize - (matchAny ? 2 : 1);
|
||||
|
||||
// Evaluate params first
|
||||
ResultHandle name = resolve.invokeInterfaceMethod(Descriptors.GET_NAME, evalContext);
|
||||
ResultHandle params = resolve.invokeInterfaceMethod(Descriptors.GET_PARAMS, evalContext);
|
||||
ResultHandle resultsArray = resolve.newArray(CompletableFuture.class,
|
||||
resolve.load(paramSize - 1));
|
||||
for (int i = 0; i < (paramSize - 1); i++) {
|
||||
resolve.load(realParamSize));
|
||||
for (int i = 0; i < realParamSize; i++) {
|
||||
ResultHandle evalResult = resolve.invokeInterfaceMethod(
|
||||
Descriptors.EVALUATE, evalContext,
|
||||
resolve.invokeInterfaceMethod(Descriptors.LIST_GET, params,
|
||||
@@ -159,7 +173,7 @@ public class ExtensionMethodGenerator {
|
||||
AssignableResultHandle whenName = null;
|
||||
if (matchAny) {
|
||||
whenName = whenComplete.createVariable(String.class);
|
||||
whenComplete.assign(whenName, resolve.invokeInterfaceMethod(Descriptors.GET_NAME, evalContext));
|
||||
whenComplete.assign(whenName, name);
|
||||
}
|
||||
AssignableResultHandle whenRet = whenComplete.createVariable(CompletableFuture.class);
|
||||
whenComplete.assign(whenRet, ret);
|
||||
@@ -177,7 +191,7 @@ public class ExtensionMethodGenerator {
|
||||
args[1] = whenName;
|
||||
shift++;
|
||||
}
|
||||
for (int i = 0; i < (paramSize - 1); i++) {
|
||||
for (int i = 0; i < realParamSize; i++) {
|
||||
ResultHandle paramResult = success.readArrayValue(whenResults, i);
|
||||
args[i + shift] = success.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_GET, paramResult);
|
||||
}
|
||||
@@ -202,6 +216,7 @@ public class ExtensionMethodGenerator {
|
||||
MethodCreator appliesTo = valueResolver.getMethodCreator("appliesTo", boolean.class, EvalContext.class)
|
||||
.setModifiers(ACC_PUBLIC);
|
||||
|
||||
List<Type> parameters = method.parameters();
|
||||
boolean matchAny = matchName.equals(TemplateExtension.ANY);
|
||||
ResultHandle evalContext = appliesTo.getMethodParam(0);
|
||||
ResultHandle base = appliesTo.invokeInterfaceMethod(Descriptors.GET_BASE, evalContext);
|
||||
@@ -211,7 +226,7 @@ public class ExtensionMethodGenerator {
|
||||
|
||||
// Test base object class
|
||||
ResultHandle baseClass = appliesTo.invokeVirtualMethod(Descriptors.GET_CLASS, base);
|
||||
ResultHandle testClass = appliesTo.loadClass(method.parameters().get(0).name().toString());
|
||||
ResultHandle testClass = appliesTo.loadClass(parameters.get(0).name().toString());
|
||||
ResultHandle baseClassTest = appliesTo.invokeVirtualMethod(Descriptors.IS_ASSIGNABLE_FROM, testClass,
|
||||
baseClass);
|
||||
BytecodeCreator baseNotAssignable = appliesTo.ifNonZero(baseClassTest).falseBranch();
|
||||
@@ -225,17 +240,14 @@ public class ExtensionMethodGenerator {
|
||||
nameNotMatched.returnValue(nameNotMatched.load(false));
|
||||
}
|
||||
|
||||
int paramSize = method.parameters().size();
|
||||
if (paramSize > 1) {
|
||||
// Test number of parameters
|
||||
ResultHandle params = appliesTo.invokeInterfaceMethod(Descriptors.GET_PARAMS, evalContext);
|
||||
ResultHandle paramsCount = appliesTo.invokeInterfaceMethod(Descriptors.COLLECTION_SIZE, params);
|
||||
BranchResult paramsTest = appliesTo
|
||||
.ifNonZero(appliesTo.invokeStaticMethod(Descriptors.INTEGER_COMPARE,
|
||||
appliesTo.load(paramSize - (matchAny ? 2 : 1)), paramsCount));
|
||||
BytecodeCreator paramsNotMatching = paramsTest.trueBranch();
|
||||
paramsNotMatching.returnValue(paramsNotMatching.load(false));
|
||||
}
|
||||
// Test number of parameters
|
||||
ResultHandle params = appliesTo.invokeInterfaceMethod(Descriptors.GET_PARAMS, evalContext);
|
||||
ResultHandle paramsCount = appliesTo.invokeInterfaceMethod(Descriptors.COLLECTION_SIZE, params);
|
||||
BranchResult paramsTest = appliesTo
|
||||
.ifNonZero(appliesTo.invokeStaticMethod(Descriptors.INTEGER_COMPARE,
|
||||
appliesTo.load(parameters.size() - (matchAny ? 2 : 1)), paramsCount));
|
||||
BytecodeCreator paramsNotMatching = paramsTest.trueBranch();
|
||||
paramsNotMatching.returnValue(paramsNotMatching.load(false));
|
||||
appliesTo.returnValue(appliesTo.load(true));
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ public class ValueResolverGenerator {
|
||||
private static final DotName OBJECT = DotName.createSimple(Object.class.getName());
|
||||
|
||||
public static final String SUFFIX = "_ValueResolver";
|
||||
public static final String NESTED_SEPARATOR = "$_";
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ValueResolverGenerator.class);
|
||||
|
||||
@@ -112,7 +113,7 @@ public class ValueResolverGenerator {
|
||||
|
||||
String baseName;
|
||||
if (clazz.enclosingClass() != null) {
|
||||
baseName = simpleName(clazz.enclosingClass()) + "_" + simpleName(clazz);
|
||||
baseName = simpleName(clazz.enclosingClass()) + NESTED_SEPARATOR + simpleName(clazz);
|
||||
} else {
|
||||
baseName = simpleName(clazz);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user