Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaTemplate matching on parameterized types #3963

Merged
merged 12 commits into from
Feb 2, 2024
Merged

Conversation

jkschneider
Copy link
Member

@jkschneider jkschneider commented Feb 1, 2024

Adding support for parameterized types in the grammar of the template parser and for matching as performed by JavaTemplate#matches().

@timtebeek timtebeek added the enhancement New feature or request label Feb 1, 2024
Also start working on producing a `JavaType` rather than a `String` representation.
In an expression like `Long.parseLong("1")` the `Long` type reference is not an expression and should not be matched by a template like `#{any(long)}`.
@knutwannheden
Copy link
Contributor

I think now it is basically working. I had to change the internal representation we use for template parameters to use a JavaType rather than a plain String for the parameter type, otherwise we can't match parameterized types.

In this area there is still some performance improvements that can be made: We should change the JavaTemplate#matcher() instance method so that it caches the matcher in a precompiled form (like Pattern#compile() basically). That would then end up caching the template parameters we create in JavaTemplateSemanticallyEqual#createTemplateParameters():

private static J[] createTemplateParameters(String code) {
PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper(
"#{", "}", null);
List<J> parameters = new ArrayList<>();
String substituted = code;
Map<String, String> typedPatternByName = new HashMap<>();
while (true) {
String previous = substituted;
substituted = propertyPlaceholderHelper.replacePlaceholders(substituted, key -> {
String s;
if (!key.isEmpty()) {
TemplateParameterParser parser = new TemplateParameterParser(new CommonTokenStream(new TemplateParameterLexer(
CharStreams.fromString(key))));
parser.removeErrorListeners();
parser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
int line, int charPositionInLine, String msg, RecognitionException e) {
throw new IllegalArgumentException(
String.format("Syntax error at line %d:%d %s.", line, charPositionInLine, msg), e);
}
});
TemplateParameterParser.MatcherPatternContext ctx = parser.matcherPattern();
if (ctx.typedPattern() == null) {
String paramName = ctx.parameterName().Identifier().getText();
s = typedPatternByName.get(paramName);
if (s == null) {
throw new IllegalArgumentException("The parameter " + paramName + " must be defined before it is referenced.");
}
} else {
TypedPatternContext typedPattern = ctx.typedPattern();
JavaType type = typedParameter(key, typedPattern);
s = TypeUtils.toString(type);
String name = null;
if (typedPattern.parameterName() != null) {
name = typedPattern.parameterName().Identifier().getText();
typedPatternByName.put(name, s);
}
Markers markers = Markers.build(Collections.singleton(new TemplateParameter(randomId(), type, name)));
parameters.add(new J.Empty(randomId(), Space.EMPTY, markers));
}
} else {
throw new IllegalArgumentException("Only typed placeholders are allowed.");
}
return s;
});
if (previous.equals(substituted)) {
break;
}
}
return parameters.toArray(new J[0]);
}

But I will leave this optimization for another PR.

Further, I am quite sure there are still bugs in the area of TypeUtils#isAssignableTo() (which has grown very organically), but also that I will leave for another day.

Copy link
Contributor

@knutwannheden knutwannheden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@knutwannheden knutwannheden marked this pull request as ready for review February 2, 2024 09:55
@knutwannheden knutwannheden changed the title JavaTemplate matching on parameterized types JavaTemplate matching on parameterized types Feb 2, 2024
@knutwannheden knutwannheden merged commit 61ffd61 into main Feb 2, 2024
1 check passed
@knutwannheden knutwannheden deleted the template-parameters branch February 2, 2024 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants