/** * Oracle's JDK8 encodes method references directly as an "invoke virtual" lambda. (Eclipse seems * to encode method references like a normal method). So here we handle this special case of an * "invoke virtual" lambda. */ protected static MethodAnalysisResults analyzeInvokeVirtual( String methodClass, String methodName, String methodSignature, MetamodelUtil metamodel, ClassLoader alternateClassLoader, boolean isObjectEqualsSafe, boolean isCollectionContainsSafe, boolean throwExceptionOnFailure) { // See if the method call is allowed. Create a fake method argument that reroutes // to be the base of the method call. MethodSignature sig = new MethodSignature(methodClass, methodName, methodSignature); Type[] argTypes = Type.getMethodType(sig.desc).getArgumentTypes(); MethodChecker checker = metamodel.getMethodChecker(isObjectEqualsSafe, isCollectionContainsSafe); TypedValue fakeBase = new TypedValue.ArgValue(sig.getOwnerType(), 0); List<TypedValue> fakeArgs = new ArrayList<>(); for (int n = 0; n < argTypes.length; n++) fakeArgs.add(new TypedValue.ArgValue(argTypes[n], n + 1)); if (OperationSideEffect.NONE != checker.isMethodSafe(sig, fakeBase, fakeArgs)) { if (throwExceptionOnFailure) throw new IllegalArgumentException( "Could not analyze lambda code. Unknown method " + sig + " encountered."); return null; } // Create a fake analysis of the methods that's composed of only a call to the given method. MethodCallValue.VirtualMethodCallValue methodCallVal = new MethodCallValue.VirtualMethodCallValue( sig.owner, sig.name, sig.desc, fakeArgs, fakeBase); MethodAnalysisResults analysis = new MethodAnalysisResults(); analysis.addPath(new ArrayList<>(), methodCallVal, new ArrayList<>()); return analysis; }
/* (non-Javadoc) * @see ch.epfl.labos.iu.orm.queryll2.PathAnalysisMethodChecker#isMethodSafe(ch.epfl.labos.iu.orm.queryll2.symbolic.MethodSignature, ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValue, java.util.List) */ @Override public OperationSideEffect isMethodSafe( MethodSignature m, TypedValue base, List<TypedValue> args) { if (isObjectEqualsSafe && objectEquals.equals(m)) { return OperationSideEffect.NONE; } else if (safeMethods.contains(m) || subqueryMethods.contains(m) || jpqlFunctionMethods.contains(m)) { return OperationSideEffect.NONE; } else { // Use reflection to get info about the method (or would it be better // to do this through direct bytecode inspection?), and see if it's // annotated as safe try { Method reflectedMethod = Annotations.asmMethodSignatureToReflectionMethod(m); // Special handling of Collection.contains() for subclasses of Collection. if (isCollectionContainsSafe && "contains".equals(m.name) && "(Ljava/lang/Object;)Z".equals(m.desc) && Collection.class.isAssignableFrom(reflectedMethod.getDeclaringClass())) return OperationSideEffect.NONE; if (Annotations.methodHasSomeAnnotations(reflectedMethod, safeMethodAnnotations)) return OperationSideEffect.NONE; } catch (ClassNotFoundException | NoSuchMethodException e) { // Eat the error } return OperationSideEffect.UNSAFE; } }
static { try { // I'm initializing some of these method signatures through reflection // instead of statically so that it's easier to find breakages due to method renaming etc. jpqlLike = MethodSignature.fromMethod(JPQL.class.getMethod("like", String.class, String.class)); jpqlIsIn = MethodSignature.fromMethod(JPQL.class.getMethod("isIn", Object.class, JinqStream.class)); jpqlIsInList = MethodSignature.fromMethod( JPQL.class.getMethod("isInList", Object.class, Collection.class)); jpqlListContains = MethodSignature.fromMethod( JPQL.class.getMethod("listContains", Collection.class, Object.class)); streamSelectAll = MethodSignature.fromMethod( JinqStream.class.getMethod("selectAll", JinqStream.Join.class)); streamSelectAllList = MethodSignature.fromMethod( JinqStream.class.getMethod("selectAllList", JinqStream.JoinToIterable.class)); streamJoinList = MethodSignature.fromMethod( JinqStream.class.getMethod("joinList", JinqStream.JoinToIterable.class)); } catch (NoSuchMethodException | SecurityException e) { throw new IllegalArgumentException( "Cannot initialize MethodChecker because it cannot find a needed method", e); } }