diff --git a/src/main/java/jef/asm/FilterMethodVisitor.java b/src/main/java/jef/asm/FilterMethodVisitor.java index ed294bf..f0152f8 100644 --- a/src/main/java/jef/asm/FilterMethodVisitor.java +++ b/src/main/java/jef/asm/FilterMethodVisitor.java @@ -18,11 +18,14 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.Stack; import java.util.function.Consumer; @@ -80,7 +83,7 @@ class FilterMethodVisitor extends MethodVisitor { @Override public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { System.out.println("method insn: " + ops.getOrDefault(opcode, "" + opcode) + ", " + owner + ", " + name + ", " + descriptor); - if (opcode == Opcodes.INVOKESTATIC) { + if (opcode == Opcodes.INVOKESTATIC && name.equals("valueOf")) { //ignore boxed primitive types var boxedPrimitiveClasses = Set.of("java/lang/Boolean", "java/lang/Integer", "java/lang/Long", "java/lang/Float", "java/lang/Double"); if (boxedPrimitiveClasses.contains(owner)) { @@ -89,18 +92,34 @@ class FilterMethodVisitor extends MethodVisitor { //do something throw new RuntimeException("method insn: unsupported opcode " + ops.getOrDefault(opcode, "" + opcode)); } - } else if (opcode == Opcodes.INVOKEINTERFACE) { + } else if (opcode == Opcodes.INVOKEINTERFACE || opcode == Opcodes.INVOKEVIRTUAL) { try { if (name.equals("contains") && owner.startsWith("java/util/") && Collection.class.isAssignableFrom(Class.forName(owner.replace("/", ".")))) { var element = varStack.pop(); var collection = varStack.pop(); -// System.out.println("element: " + element); -// System.out.println("collection: " + collection); varStack.push(new BinaryExpression(element, collection, BinaryExpression.Operator.IN)); + } else if (name.startsWith("get") && name.length() > 3 && descriptor.startsWith("()")) { //hacky getter support, TODO replace this with proper getter eval later + var field = findField(owner, name); + if (field.isPresent()) { + var v = varStack.pop(); + if (v instanceof ParameterExpression p) { + if (p.isInput()) { + varStack.push(new FieldExpression(field.get().getName(), descriptor.substring(2))); + } else { + throw new RuntimeException("method insn: getter support only to predicate parameter"); + } + } else { + throw new RuntimeException("method insn: getter support expected ParameterExpression but found" + v.getClass().getSimpleName()); + } + } else { + throw new RuntimeException("method insn: could not find field for getter " + name + " in " + owner); + } + } else { + throw new RuntimeException("method insn: unsupported function " + name + " in " + owner); } - } catch (ClassNotFoundException e) { + } catch (Exception e) { throw new RuntimeException("method insn: ", e); } } else { @@ -447,4 +466,19 @@ class FilterMethodVisitor extends MethodVisitor { System.out.println("-------------------> " + new WhereExpression(new SelectExpression(List.of("*"), new TableExpression("dummy"), ""), varStack.peek())); } } + + private static Optional findField(String owner, String name) throws Exception { + var cls = Class.forName(owner.replace("/", ".")); + String fieldname = name.substring(3, 4).toLowerCase(Locale.ROOT) + name.substring(4); + var field = cls.getDeclaredField(fieldname); + if (field != null) { + return Optional.of(field); + } + for (Field declaredField : cls.getDeclaredFields()) { + if (declaredField.getName().equalsIgnoreCase(fieldname)) { + return Optional.of(declaredField); + } + } + return Optional.empty(); + } } diff --git a/src/test/java/jef/operations/FilterOpTest.java b/src/test/java/jef/operations/FilterOpTest.java index b25cb9f..133e80b 100644 --- a/src/test/java/jef/operations/FilterOpTest.java +++ b/src/test/java/jef/operations/FilterOpTest.java @@ -1,6 +1,7 @@ package jef.operations; import jef.DBSet; +import lombok.Getter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -207,10 +208,15 @@ public class FilterOpTest { } @Test - public void test() { - + public void testMemberViaGetter() { + String act; + act = new DBSet("table1") + .filter(e -> e.getI() == 1337) + .toString(); + Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.i = 1337", act); } + @Getter public static class TestClass implements Serializable { public int i = 1; public Object o = new Object();