Make SpelNode compilation aware

In order to make SpelNode compilation aware, this method moves the
declaration of isCompilable() and generateCode(...) from SpelNodeImpl
to SpelNode.

Closes gh-32707
This commit is contained in:
Sam Brannen 2024-04-25 13:47:57 +03:00
parent 14689256c4
commit 8f579b3144
2 changed files with 38 additions and 21 deletions

View File

@ -16,6 +16,7 @@
package org.springframework.expression.spel;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
@ -25,6 +26,7 @@ import org.springframework.lang.Nullable;
* Expression Language (SpEL) expression.
*
* @author Andy Clement
* @author Sam Brannen
* @since 3.0
*/
public interface SpelNode {
@ -109,4 +111,40 @@ public interface SpelNode {
*/
int getEndPosition();
/**
* Determine if this node can be compiled to bytecode.
* <p>The reasoning in each node may be different but will typically involve
* checking whether the exit type descriptor of the node is known and any
* relevant child nodes are compilable.
* <p>The default implementation returns {@code false}.
* <p>If you override this method, you must also override
* {@link #generateCode(MethodVisitor, CodeFlow)}.
* @return {@code true} if this node can be compiled to bytecode
* @since 6.2
* @see #generateCode(MethodVisitor, CodeFlow)
*/
default boolean isCompilable() {
return false;
}
/**
* Generate the bytecode for this node into the supplied {@link MethodVisitor}.
* <p>Context information about the current expression being compiled is
* available in the supplied {@link CodeFlow} object &mdash; for example,
* information about the type of the object currently on the stack.
* <p>This method will not be invoked unless {@link #isCompilable()} returns
* {@code true}.
* <p>The default implementation throws an {@link IllegalStateException}
* since {@link #isCompilable()} returns {@code false} by default.
* <p>If you override this method, you must also override {@link #isCompilable()}.
* @param methodVisitor the ASM {@code MethodVisitor} into which code should
* be generated
* @param codeFlow a context object with information about what is on the stack
* @since 6.2
* @see #isCompilable()
*/
default void generateCode(MethodVisitor methodVisitor, CodeFlow codeFlow) {
throw new IllegalStateException(getClass().getName() + " does not support bytecode generation");
}
}

View File

@ -191,27 +191,6 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
return false;
}
/**
* Check whether a node can be compiled to bytecode. The reasoning in each node may
* be different but will typically involve checking whether the exit type descriptor
* of the node is known and any relevant child nodes are compilable.
* @return {@code true} if this node can be compiled to bytecode
*/
public boolean isCompilable() {
return false;
}
/**
* Generate the bytecode for this node into the supplied visitor. Context info about
* the current expression being compiled is available in the codeflow object, e.g.
* including information about the type of the object currently on the stack.
* @param mv the ASM MethodVisitor into which code should be generated
* @param cf a context object with info about what is on the stack
*/
public void generateCode(MethodVisitor mv, CodeFlow cf) {
throw new IllegalStateException(getClass().getName() +" has no generateCode(..) method");
}
@Nullable
public String getExitDescriptor() {
return this.exitTypeDescriptor;