From 284bf647b4781e853c4483d3741f523fd6342fda Mon Sep 17 00:00:00 2001 From: wea_ondara Date: Thu, 8 Sep 2022 19:24:55 +0200 Subject: [PATCH] resolve getters --- src/main/java/jef/asm/AsmParser.java | 35 +++++++++++++++++-- src/main/java/jef/asm/OptimizedAsmParser.java | 6 ++++ .../model/ForeignKeyExposeInitializer.java | 24 +++++++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/main/java/jef/asm/AsmParser.java b/src/main/java/jef/asm/AsmParser.java index e17556a..516f2ab 100644 --- a/src/main/java/jef/asm/AsmParser.java +++ b/src/main/java/jef/asm/AsmParser.java @@ -9,29 +9,43 @@ import org.objectweb.asm.Opcodes; import java.io.InputStream; import java.io.Serializable; import java.lang.invoke.SerializedLambda; +import java.lang.reflect.Method; import java.util.stream.IntStream; @Getter public class AsmParser { private final Serializable lambda; + private final Method method; public AsmParser(SerializablePredicate predicate) { this.lambda = predicate; + this.method = null; } public AsmParser(SerializableFunction function) { this.lambda = function; + this.method = null; + } + + public AsmParser(Method method) { + this.lambda = null; + this.method = method; } public AsmParseResult parse() throws AsmParseException { try { - return parseExpression(); + if (this.lambda != null) { + return parseLambdaExpression(); + } else if (this.method != null) { + return parseMethodExpression(); + } + throw new IllegalStateException(); } catch (Exception e) { throw new AsmParseException("PredicateParser: failed to parse expression: " + e.getLocalizedMessage(), e); } } - private AsmParseResult parseExpression() throws Exception { + private AsmParseResult parseLambdaExpression() throws Exception { var cls = lambda.getClass(); var loader = cls.getClassLoader(); InputStream is; @@ -53,4 +67,21 @@ public class AsmParser { return visiter.getResult(); } + + private AsmParseResult parseMethodExpression() throws Exception { + var cls = method.getClass(); + var loader = cls.getClassLoader(); + InputStream is = loader.getResourceAsStream(cls.getName().replace(".", "/") + ".class"); + Object[] args = new Object[0];//TODO capturing args here? or maybe not supported since this will only be user by getter evaluation + + return parseCommon(is, method.getName(), args); + } + + private AsmParseResult parseCommon(InputStream classIs, String methodname, Object[] args) throws Exception { + var cr = new ClassReader(classIs); + var visiter = new FilterClassVisitor(Opcodes.ASM9, methodname, args); + cr.accept(visiter, 0); + + return visiter.getResult(); + } } diff --git a/src/main/java/jef/asm/OptimizedAsmParser.java b/src/main/java/jef/asm/OptimizedAsmParser.java index a545fde..d28f8ec 100644 --- a/src/main/java/jef/asm/OptimizedAsmParser.java +++ b/src/main/java/jef/asm/OptimizedAsmParser.java @@ -7,6 +7,8 @@ import jef.serializable.SerializableFunction; import jef.serializable.SerializablePredicate; import lombok.Getter; +import java.lang.reflect.Method; + @Getter public class OptimizedAsmParser extends AsmParser { @@ -18,6 +20,10 @@ public class OptimizedAsmParser extends AsmParser { super(function); } + public OptimizedAsmParser(Method method) { + super(method); + } + public AsmParseResult parse() throws AsmParseException { var result = super.parse(); var expr = result.getExpression(); diff --git a/src/main/java/jef/model/ForeignKeyExposeInitializer.java b/src/main/java/jef/model/ForeignKeyExposeInitializer.java index ebf2214..4bf817b 100644 --- a/src/main/java/jef/model/ForeignKeyExposeInitializer.java +++ b/src/main/java/jef/model/ForeignKeyExposeInitializer.java @@ -1,7 +1,9 @@ package jef.model; +import jef.asm.OptimizedAsmParser; import jef.model.annotations.ForeignKey; import jef.serializable.SerializableObject; +import jef.util.Util; import java.util.Locale; @@ -31,26 +33,34 @@ class ForeignKeyExposeInitializer {//TODO testcases for this class if (anno.entity() != SerializableObject.class) { // not a foreign key exposure return false; } - return f.getField().getName().equals(anno.getterOrField());//TODO support getters + var fieldname = anno.getterOrField(); //TODO test + + //if getter, extract getter field + var method = Util.tryGet(() -> entityBuilder.type().orElseThrow().getMethod(anno.getterOrField())); //TODO test + if (method.isPresent()) { + var res = new OptimizedAsmParser(method.get()).parse(); + fieldname = res.getAccessedFields().stream().findFirst().orElseThrow().getName(); + } + return f.getField().getName().equals(fieldname); } //only allow fields with same prefix if (!e.getField().getName().startsWith(f.getField().getName())) { return false; } //match id field which ends in Id or Fk - if (e.getField().getName().equals(f.getField().getName() + "Id") - || e.getField().getName().equals(f.getField().getName() + "ID") - || e.getField().getName().equals(f.getField().getName() + "Fk") - || e.getField().getName().equals(f.getField().getName() + "FK")) { + if (e.getField().getName().equals(f.getField().getName() + "Id") //TODO test + || e.getField().getName().equals(f.getField().getName() + "ID") //TODO test + || e.getField().getName().equals(f.getField().getName() + "Fk") //TODO test + || e.getField().getName().equals(f.getField().getName() + "FK")) { //TODO test return true; } //match id field which ends in the name of the primary key field of the referenced entity - var other = mb.getEntity(f.getField().getTypeName()); + var other = mb.getEntity(f.getField().getTypeName()); //TODO test if (other == null || other.getPrimaryKey() == null) { return false; } //assumption: initializing from models only has primary keys with 1 field (no composite keys) - var x = other.getPrimaryKey().getFields().get(0).getName(); + var x = other.getPrimaryKey().getFields().get(0).getName(); //TODO test x = x.substring(0, 1).toUpperCase(Locale.ROOT) + x.substring(1); return e.getField().getName().equals(f.getField().getName() + x); }).toList();