-
Notifications
You must be signed in to change notification settings - Fork 38.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow MethodReference to define a more flexible signature
This commit moves MethodReference to an interface with a default implementation that relies on a MethodSpec. Such an arrangement avoid the need of specifying attributes of the method such as whether it is static or not. The resolution of the invocation block now takes an ArgumentCodeGenerator rather than the raw arguments. Doing so gives the opportunity to create more flexible signatures. See gh-29005
- Loading branch information
Showing
16 changed files
with
469 additions
and
428 deletions.
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
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
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
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
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
134 changes: 134 additions & 0 deletions
134
spring-core/src/main/java/org/springframework/aot/generate/DefaultMethodReference.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,134 @@ | ||
/* | ||
* Copyright 2002-2022 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.aot.generate; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import javax.lang.model.element.Modifier; | ||
|
||
import org.springframework.javapoet.ClassName; | ||
import org.springframework.javapoet.CodeBlock; | ||
import org.springframework.javapoet.MethodSpec; | ||
import org.springframework.javapoet.TypeName; | ||
import org.springframework.lang.Nullable; | ||
import org.springframework.util.Assert; | ||
|
||
/** | ||
* Default {@link MethodReference} implementation based on a {@link MethodSpec}. | ||
* | ||
* @author Stephane Nicoll | ||
* @author Phillip Webb | ||
* @since 6.0 | ||
*/ | ||
public class DefaultMethodReference implements MethodReference { | ||
|
||
private final MethodSpec method; | ||
|
||
@Nullable | ||
private final ClassName declaringClass; | ||
|
||
public DefaultMethodReference(MethodSpec method, @Nullable ClassName declaringClass) { | ||
this.method = method; | ||
this.declaringClass = declaringClass; | ||
} | ||
|
||
@Override | ||
public CodeBlock toCodeBlock() { | ||
String methodName = this.method.name; | ||
if (isStatic()) { | ||
Assert.notNull(this.declaringClass, "static method reference must define a declaring class"); | ||
return CodeBlock.of("$T::$L", this.declaringClass, methodName); | ||
} | ||
else { | ||
return CodeBlock.of("this::$L", methodName); | ||
} | ||
} | ||
|
||
public CodeBlock toInvokeCodeBlock(ArgumentCodeGenerator argumentCodeGenerator, | ||
@Nullable ClassName targetClassName) { | ||
String methodName = this.method.name; | ||
CodeBlock.Builder code = CodeBlock.builder(); | ||
if (isStatic()) { | ||
Assert.notNull(this.declaringClass, "static method reference must define a declaring class"); | ||
if (isSameDeclaringClass(targetClassName)) { | ||
code.add("$L", methodName); | ||
} | ||
else { | ||
code.add("$T.$L", this.declaringClass, methodName); | ||
} | ||
} | ||
else { | ||
if (!isSameDeclaringClass(targetClassName)) { | ||
code.add(instantiateDeclaringClass(this.declaringClass)); | ||
} | ||
code.add("$L", methodName); | ||
} | ||
code.add("("); | ||
addArguments(code, argumentCodeGenerator); | ||
code.add(")"); | ||
return code.build(); | ||
} | ||
|
||
/** | ||
* Add the code for the method arguments using the specified | ||
* {@link ArgumentCodeGenerator} if necessary. | ||
* @param code the code builder to use to add method arguments | ||
* @param argumentCodeGenerator the code generator to use | ||
*/ | ||
protected void addArguments(CodeBlock.Builder code, ArgumentCodeGenerator argumentCodeGenerator) { | ||
List<CodeBlock> arguments = new ArrayList<>(); | ||
TypeName[] argumentTypes = this.method.parameters.stream() | ||
.map(parameter -> parameter.type).toArray(TypeName[]::new); | ||
for (int i = 0; i < argumentTypes.length; i++) { | ||
TypeName argumentType = argumentTypes[i]; | ||
CodeBlock argumentCode = argumentCodeGenerator.generateCode(argumentType); | ||
if (argumentCode == null) { | ||
throw new IllegalArgumentException("Could not generate code for " + this | ||
+ ": parameter " + i + " of type " + argumentType + " is not supported"); | ||
} | ||
arguments.add(argumentCode); | ||
} | ||
code.add(CodeBlock.join(arguments, ", ")); | ||
} | ||
|
||
protected CodeBlock instantiateDeclaringClass(ClassName declaringClass) { | ||
return CodeBlock.of("new $T().", declaringClass); | ||
} | ||
|
||
private boolean isStatic() { | ||
return this.method.modifiers.contains(Modifier.STATIC); | ||
} | ||
|
||
private boolean isSameDeclaringClass(ClassName declaringClass) { | ||
return this.declaringClass == null || this.declaringClass.equals(declaringClass); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
String methodName = this.method.name; | ||
if (isStatic()) { | ||
return this.declaringClass + "::" + methodName; | ||
} | ||
else { | ||
return ((this.declaringClass != null) | ||
? "<" + this.declaringClass + ">" : "<instance>") | ||
+ "::" + methodName; | ||
} | ||
} | ||
|
||
} |
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
Oops, something went wrong.