diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index ee7d6eddebdb..9af3e5727955 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -1232,7 +1232,6 @@ public ResolvedJavaMethod[] getDeclaredMethods() { @Override public AnalysisMethod[] getDeclaredMethods(boolean forceLink) { - GraalError.guarantee(forceLink == false, "only use getDeclaredMethods without forcing to link, because linking can throw LinkageError"); return universe.lookup(wrapped.getDeclaredMethods(forceLink)); } @@ -1243,7 +1242,6 @@ public ResolvedJavaMethod[] getDeclaredConstructors() { @Override public AnalysisMethod[] getDeclaredConstructors(boolean forceLink) { - GraalError.guarantee(forceLink == false, "only use getDeclaredConstructors without forcing to link, because linking can throw LinkageError"); return universe.lookup(wrapped.getDeclaredConstructors(forceLink)); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index ef90adec30d6..89fefe8e9f53 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -45,7 +45,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import com.oracle.svm.hosted.prophet.ProphetPlugin; import org.graalvm.collections.Pair; import org.graalvm.compiler.core.riscv64.ShadowedRISCV64; import org.graalvm.compiler.debug.DebugContext; @@ -78,6 +77,7 @@ import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.option.HostedOptionParser; +import com.oracle.svm.hosted.prophet.ProphetPlugin; import com.oracle.svm.util.ClassUtil; import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ModuleSupport; @@ -531,9 +531,6 @@ private int buildImage(ImageClassLoader classLoader) { reporter.printStart(imageName, imageKind); } - int maxConcurrentThreads = NativeImageOptions.getMaximumNumberOfConcurrentThreads(parsedHostedOptions); - analysisExecutor = NativeImagePointsToAnalysis.createExecutor(debug, NativeImageOptions.getMaximumNumberOfAnalysisThreads(parsedHostedOptions)); - compilationExecutor = NativeImagePointsToAnalysis.createExecutor(debug, maxConcurrentThreads); /* * Since the main thread helps to process analysis and compilation tasks (see use of * awaitQuiescence() in CompletionExecutor), subtract one to determine the number of diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EndpointExtraction.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EndpointExtraction.java index b26342f9b2a7..257777e07c5f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EndpointExtraction.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EndpointExtraction.java @@ -1,50 +1,21 @@ package com.oracle.svm.hosted.prophet; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.reachability.ReachabilityAnalysisMethod; -import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.hosted.ImageClassLoader; -import com.oracle.svm.hosted.analysis.Inflation; -import com.oracle.svm.hosted.prophet.model.Endpoint; -import com.oracle.svm.hosted.prophet.model.Entity; -import com.oracle.svm.hosted.prophet.model.Field; -import com.oracle.svm.hosted.prophet.model.Module; -import com.oracle.svm.hosted.prophet.model.Name; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodes.CallTargetNode; -import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.InvokeWithExceptionNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.options.Option; -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; -import org.graalvm.polyglot.*; -import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; -import org.graalvm.compiler.nodes.ConstantNode; -import com.oracle.truffle.api.nodes.RootNode; -import org.graalvm.compiler.nodes.CallTargetNode; -import java.lang.reflect.Method; -import org.graalvm.polyglot.HostAccess; - -import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; -import javax.xml.transform.Result; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.hosted.analysis.Inflation; +import com.oracle.svm.hosted.prophet.model.Endpoint; -import java.util.Collection; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; public class EndpointExtraction { @@ -53,14 +24,16 @@ public class EndpointExtraction { private final static String POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping"; private final static String DELETE_MAPPING = "org.springframework.web.bind.annotation.DeleteMapping"; - //annotations for controller to get endpoints + // annotations for controller to get endpoints private static final Set controllerAnnotationNames = new HashSet<>(Arrays.asList("GetMapping", "PutMapping", "DeleteMapping", "PostMapping")); + public static Set extractEndpoints(Class clazz, AnalysisMetaAccess metaAccess, Inflation bb, String msName) { AnalysisType analysisType = metaAccess.lookupJavaType(clazz); Set endpoints = new HashSet(); try { - //Obtaining the class path (which will be combined with the method's path for a full URI) + // Obtaining the class path (which will be combined with the method's path for a full + // URI) Annotation[] annotationsClass = clazz.getAnnotations(); String[] fullPath = null; boolean hasFullPath = false; @@ -69,24 +42,26 @@ public static Set extractEndpoints(Class clazz, AnalysisMetaAccess Method pathMethod = annotationClass.annotationType().getMethod("value"); fullPath = (String[]) pathMethod.invoke(annotationClass); hasFullPath = true; - //System.out.println(fullPath[0]); + // System.out.println(fullPath[0]); } } - for (AnalysisMethod method : analysisType.getDeclaredMethods()) { - try { - // What I will need to extract: String httpMethod, String parentMethod, String arguments, String returnType - Annotation[] annotations = method.getAnnotations(); + for (AnalysisMethod method : ((AnalysisMethod[]) analysisType.getDeclaredMethods())) { + try { + // What I will need to extract: String httpMethod, String parentMethod, String + // arguments, String returnType + Annotation[] annotations = method.getWrapped().getAnnotations(); for (Annotation annotation : annotations) { - + ArrayList parameterAnnotationsList = new ArrayList<>(); String httpMethod = null, parentMethod = null, returnTypeResult = null, path = ""; boolean returnTypeCollection = false, isEndpoint = false; if (controllerAnnotationNames.contains(annotation.annotationType().getSimpleName())) { isEndpoint = true; - //Code to get the parentMethod attribute: - //following the rad-source format for the parentMethod JSON need to parse before the first parenthesis - parentMethod = method.getQualifiedName().substring(0,method.getQualifiedName().indexOf("(")); + // Code to get the parentMethod attribute: + // following the rad-source format for the parentMethod JSON need to + // parse before the first parenthesis + parentMethod = method.getQualifiedName().substring(0, method.getQualifiedName().indexOf("(")); if (annotation.annotationType().getName().startsWith(PUT_MAPPING)) { httpMethod = "PUT"; } else if (annotation.annotationType().getName().startsWith(GET_MAPPING)) { @@ -97,100 +72,113 @@ public static Set extractEndpoints(Class clazz, AnalysisMetaAccess httpMethod = "DELETE"; } - //try to get the path (might be null) - //Example of a path to parse: @org.springframework.web.bind.annotation.DeleteMapping(path={}, headers={}, name="", produces={}, - //params={}, value={"/{userId}"}, consumes={}) - + // try to get the path (might be null) + // Example of a path to parse: + // @org.springframework.web.bind.annotation.DeleteMapping(path={}, + // headers={}, name="", produces={}, + // params={}, value={"/{userId}"}, consumes={}) + boolean hasPath = false; - try{ - //System.out.println("Annotation object: " + annotation.toString()); - // path is optional, thus attempting to get it and return null if so. + try { + // System.out.println("Annotation object: " + + // annotation.toString()); + // path is optional, thus attempting to get it and return null if + // so. path = ((String[]) annotation.annotationType().getMethod("value").invoke(annotation))[0]; hasPath = true; - }catch(ArrayIndexOutOfBoundsException ex){ + } catch (ArrayIndexOutOfBoundsException ex) { hasPath = false; } - //Have to also consider the "path" JSON attribute of the annotation, (Example from train-tickets admin-user service): - //@org.springframework.web.bind.annotation.GetMapping(path={"/welcome"}, headers={}, name="", produces={}, params={}, - //value={}, consumes={}) - //This is with the assumption that a value == path when within an annotation! - if(!hasPath){ - try{ + // Have to also consider the "path" JSON attribute of the annotation, + // (Example from train-tickets admin-user service): + // @org.springframework.web.bind.annotation.GetMapping(path={"/welcome"}, + // headers={}, name="", produces={}, params={}, + // value={}, consumes={}) + // This is with the assumption that a value == path when within an + // annotation! + if (!hasPath) { + try { path = ((String[]) annotation.annotationType().getMethod("path").invoke(annotation))[0]; - }catch(ArrayIndexOutOfBoundsException ex){} + } catch (ArrayIndexOutOfBoundsException ex) { + } } parameterAnnotationsList = extractArguments(method); returnTypeResult = extractReturnType(method); - if(returnTypeResult.startsWith("[L") && isCollection(returnTypeResult)){ + if (returnTypeResult.startsWith("[L") && isCollection(returnTypeResult)) { returnTypeCollection = true; returnTypeResult = returnTypeResult.substring(2); - }else{ + } else { returnTypeCollection = isCollection(returnTypeResult); } - //Special case for request mapping - }else if (annotation.annotationType().getSimpleName().equals("RequestMapping")){ + // Special case for request mapping + } else if (annotation.annotationType().getSimpleName().equals("RequestMapping")) { isEndpoint = true; - //Code to get the parentMethod attribute: - parentMethod = method.getQualifiedName().substring(0,method.getQualifiedName().indexOf("(")); + // Code to get the parentMethod attribute: + parentMethod = method.getQualifiedName().substring(0, method.getQualifiedName().indexOf("(")); - - /* example of this case (in cms microservice): - * @CrossOrigin - @RequestMapping(path = "/{id}/detail", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public List getExamDetail(@PathVariable Integer id) { + /* + * example of this case (in cms microservice): + * + * @CrossOrigin + * + * @RequestMapping(path = "/{id}/detail", method = RequestMethod.GET, + * produces = MediaType.APPLICATION_JSON_VALUE) public List + * getExamDetail(@PathVariable Integer id) { */ String[] pathArr = (String[]) annotation.annotationType().getMethod("path").invoke(annotation); - //path = pathArr.length > 0 ? pathArr[0] : null; + // path = pathArr.length > 0 ? pathArr[0] : null; path = pathArr.length > 0 ? pathArr[0] : ""; - - //case where this is needed: + // case where this is needed: /* * ems microservice: - * @CrossOrigin - @RequestMapping(value = "/submit/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public Exam submitExam(@PathVariable("id") Integer id) { - * - * NOTE: This is a second attempt at fetching the path! (if the first approach above does not work!) + * + * @CrossOrigin + * + * @RequestMapping(value = "/submit/{id}", method = RequestMethod.GET, + * produces = MediaType.APPLICATION_JSON_VALUE) public Exam + * submitExam(@PathVariable("id") Integer id) { + * + * NOTE: This is a second attempt at fetching the path! (if the first + * approach above does not work!) */ - if(pathArr.length <= 0){ + if (pathArr.length <= 0) { String[] valueArr = (String[]) annotation.annotationType().getMethod("value").invoke(annotation); path = valueArr.length > 0 ? valueArr[0] : ""; } - - - //cant use a string[] because of ClassCastException + // cant use a string[] because of ClassCastException Object[] methods = (Object[]) annotation.annotationType().getMethod("method").invoke(annotation); if (methods.length > 0 && methods != null) { httpMethod = methods[0].toString(); } - parameterAnnotationsList = extractArguments(method); + parameterAnnotationsList = extractArguments(method); returnTypeResult = extractReturnType(method); - if(returnTypeResult.startsWith("[L") && isCollection(returnTypeResult)){ + if (returnTypeResult.startsWith("[L") && isCollection(returnTypeResult)) { returnTypeCollection = true; returnTypeResult = returnTypeResult.substring(2); - }else{ + } else { returnTypeCollection = isCollection(returnTypeResult); } } - if(isEndpoint) { + if (isEndpoint) { - //add the controller path as well (if it has a RequestMapping annotation) + // add the controller path as well (if it has a RequestMapping + // annotation) String returnedPath = path; - if(hasFullPath){ + if (hasFullPath) { returnedPath = fullPath[0] + path; } - + // System.out.println("HTTP Method: " + httpMethod); // System.out.println("Path: " + returnedPath); // System.out.println("parentMethod: " + parentMethod); // for(String value : parameterAnnotationsList){ - // System.out.println("argument: " + value); + // System.out.println("argument: " + value); // } // System.out.println("Return type: " + returnTypeResult); // System.out.println("Is Collection: " + returnTypeCollection); @@ -211,100 +199,102 @@ public Exam submitExam(@PathVariable("id") Integer id) { return endpoints; } - private static boolean isCollection(String returnType){ - if (returnType == null || returnType.equals("null")){ + private static boolean isCollection(String returnType) { + if (returnType == null || returnType.equals("null")) { return false; } - //graal api indicates collections in return type with "class [L" OR + // graal api indicates collections in return type with "class [L" OR return returnType.startsWith("[L") || returnType.matches(".*[<].*[>]"); } /** - * Method extracts and cleans the return type value of a controller method (based on a collection or object/primitive data type) + * Method extracts and cleans the return type value of a controller method (based on a + * collection or object/primitive data type) + * * @param method an AnalysisMethod * @return the method's return type as a string value */ - public static String extractReturnType(AnalysisMethod method){ + public static String extractReturnType(AnalysisMethod method) { Method javaMethod = (Method) method.getJavaMethod(); Type returnType = javaMethod.getGenericReturnType(); - //checking if return type is a collection - if(returnType instanceof ParameterizedType) { + // checking if return type is a collection + if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; Type[] typeArgs = type.getActualTypeArguments(); boolean exceptionOccurred = false; Class collectionType = null, elementType = null; - try{ + try { collectionType = (Class) type.getRawType(); elementType = (Class) typeArgs[0]; - }catch(ClassCastException ex){ - //example where this would occur: + } catch (ClassCastException ex) { + // example where this would occur: /* - @CrossOrigin - @DeleteMapping("/{cateogryId}") - public ResponseEntity deleteCateogry(@PathVariable Long cateogryId) + * @CrossOrigin + * + * @DeleteMapping("/{cateogryId}") public ResponseEntity + * deleteCateogry(@PathVariable Long cateogryId) */ exceptionOccurred = true; } - - //objective: convert interface java.util.List -> java.util.List - //double checking that it is "interface" portion removed (and not something else) - if(collectionType.toString().substring(0,9).equalsIgnoreCase("interface")){ + // objective: convert interface java.util.List -> java.util.List + // double checking that it is "interface" portion removed (and not something else) + if (collectionType.toString().substring(0, 9).equalsIgnoreCase("interface")) { String result = collectionType.toString().substring(10); - if(!exceptionOccurred){ + if (!exceptionOccurred) { result = result + "<" + elementType.toString().substring(6) + ">"; - }else{ + } else { result = result + ""; } return result; - //System.out.println("TESTING PARSING: " + result); - }else { - //TODO: need to handle Set, or other collection times (where this will break) + // System.out.println("TESTING PARSING: " + result); + } else { + // TODO: need to handle Set, or other collection times (where this will break) - if(!exceptionOccurred){ + if (!exceptionOccurred) { return collectionType.toString() + "<" + elementType.toString() + ">"; - }else{ + } else { return collectionType.toString() + ""; } } // }else if(collectionType.toString().substring(0,3).equalsIgnoreCase("set")){ - // //handle the case of a set: + // //handle the case of a set: - // String result = collectionType.toString().substring(4); - // result = result + "<" + elementType.toString().substring(6) + ">"; - // return result; + // String result = collectionType.toString().substring(4); + // result = result + "<" + elementType.toString().substring(6) + ">"; + // return result; // } - //System.out.println("Collection: " + collectionType); - //System.out.println("Element: " + elementType); - }else { + // System.out.println("Collection: " + collectionType); + // System.out.println("Element: " + elementType); + } else { - //case of just void, need to check the length of the string first - //case of just a non-collection (object or primitive value) returned: - if(returnType.toString().length() == 5 && returnType.toString().substring(0,5).equalsIgnoreCase("class")){ + // case of just void, need to check the length of the string first + // case of just a non-collection (object or primitive value) returned: + if (returnType.toString().length() == 5 && returnType.toString().substring(0, 5).equalsIgnoreCase("class")) { return returnType.toString().substring(6); - }else{ + } else { return returnType.toString(); } - //System.out.println("Return Type: " + returnType); + // System.out.println("Return Type: " + returnType); } } /* Helper function to extract arguments from a method */ public static ArrayList extractArguments(AnalysisMethod method) { - - //Code to get the argument attribute: + + // Code to get the argument attribute: // Example: "arguments": "[@PathVariable Integer id]", ArrayList parameterAnnotationsList = new ArrayList<>(); Parameter[] params = method.getParameters(); Annotation[][] annotations1 = method.getParameterAnnotations(); - + for (int i = 0; i < params.length; i++) { Annotation[] annotations2 = annotations1[i]; - //Parameter Annotations (e.g., @PathVariable) are optional, thus can be empty (null) + // Parameter Annotations (e.g., @PathVariable) are optional, thus can be empty (null) String parameterAnnotation = ""; for (int j = 0; j < annotations2.length; j++) { Annotation annotation3 = annotations2[j]; @@ -312,7 +302,7 @@ public static ArrayList extractArguments(AnalysisMethod method) { } String parameterType = params[i].getParameterizedType().toString(); String parameterName = params[i].getName(); - String simpleParameterType = parameterType.substring(parameterType.lastIndexOf(".")+1); + String simpleParameterType = parameterType.substring(parameterType.lastIndexOf(".") + 1); String fullParameter = parameterAnnotation + " " + simpleParameterType + " " + parameterName; parameterAnnotationsList.add(fullParameter); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EntityExtraction.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EntityExtraction.java index e497bff61032..ce6e953730d9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EntityExtraction.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/EntityExtraction.java @@ -1,39 +1,23 @@ package com.oracle.svm.hosted.prophet; +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.reachability.ReachabilityAnalysisMethod; - -import java.lang.annotation.Annotation; -import java.util.*; - +import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.prophet.model.Entity; import com.oracle.svm.hosted.prophet.model.Field; import com.oracle.svm.hosted.prophet.model.Name; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodes.CallTargetNode; -import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.InvokeWithExceptionNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.options.Option; -import com.oracle.svm.hosted.analysis.Inflation; -import com.oracle.svm.util.AnnotationWrapper; -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import com.oracle.svm.util.AnnotationWrapper; - -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; - -import java.lang.reflect.Type; -import java.lang.reflect.ParameterizedType; public class EntityExtraction { @@ -47,81 +31,78 @@ public static Optional extractClassEntityCalls(Class clazz, AnalysisM AnalysisType analysisType = metaAccess.lookupJavaType(clazz); try { - for (AnalysisField field : analysisType.getInstanceFields(false)) { + for (ResolvedJavaField f : analysisType.getInstanceFields(false)) { + AnalysisField field = (AnalysisField) f; String fieldName = field.getName(); try { // Spring if (field.getWrapped().getAnnotations().length > 0 || isLombok(analysisType)) { String typeName = field.getWrapped().getType().toString(); - //Handles HotSpotType and HotSpotResolvedPrimitiveType - if(typeName.contains("/") && typeName.contains(";")){ + // Handles HotSpotType and HotSpotResolvedPrimitiveType + if (typeName.contains("/") && typeName.contains(";")) { typeName = typeName.substring(typeName.lastIndexOf("/") + 1, typeName.indexOf(";")); - }else if(typeName.contains(PRIMITIVE_VALUE)){ + } else if (typeName.contains(PRIMITIVE_VALUE)) { typeName = typeName.replace(PRIMITIVE_VALUE, ""); typeName = typeName.replace(">", ""); } // Sets if it is a collection or reference based on type - if(typeName.equals("Set") || typeName.equals("List") || typeName.equals("Queue") - || typeName.equals("Deque") || typeName.equals("Map") || typeName.equals("Array")){ - - - java.lang.reflect.Field field2 = clazz.getDeclaredField(field.getWrapped().getName()); - Type genericType = field2.getGenericType(); - ParameterizedType parameterizedType = (ParameterizedType) genericType; - Type[] typeArguments = parameterizedType.getActualTypeArguments(); - String elementName = typeName + "<"; - for(Type elementType : typeArguments){ - int lastIndex = elementType.getTypeName().lastIndexOf('.'); - if(lastIndex != -1){ - elementName = elementName + elementType.getTypeName().substring(lastIndex + 1) + ","; - }else{ - throw new IllegalArgumentException("ParameterizedType does not contain any periods in EntityExtraction.java"); - } - } - elementName = elementName.substring(0, elementName.length() - 1); - if(typeArguments.length != 0){ - elementName += ">"; + if (typeName.equals("Set") || typeName.equals("List") || typeName.equals("Queue") || typeName.equals("Deque") || typeName.equals("Map") || typeName.equals("Array")) { + + java.lang.reflect.Field field2 = clazz.getDeclaredField(field.getWrapped().getName()); + Type genericType = field2.getGenericType(); + ParameterizedType parameterizedType = (ParameterizedType) genericType; + Type[] typeArguments = parameterizedType.getActualTypeArguments(); + String elementName = typeName + "<"; + for (Type elementType : typeArguments) { + int lastIndex = elementType.getTypeName().lastIndexOf('.'); + if (lastIndex != -1) { + elementName = elementName + elementType.getTypeName().substring(lastIndex + 1) + ","; + } else { + throw new IllegalArgumentException("ParameterizedType does not contain any periods in EntityExtraction.java"); } - + } + elementName = elementName.substring(0, elementName.length() - 1); + if (typeArguments.length != 0) { + elementName += ">"; + } fieldMap.putIfAbsent(fieldName, new Field(new Name(fieldName), elementName, null, true, elementName, true)); - }else if(typeName.equals("byte") || typeName.equals("short") || typeName.equals("int") - || typeName.equals("long") || typeName.equals("float") || typeName.equals("double") - || typeName.equals("char") || typeName.equals("boolean")){ + } else if (typeName.equals("byte") || typeName.equals("short") || typeName.equals("int") || typeName.equals("long") || typeName.equals("float") || typeName.equals("double") || + typeName.equals("char") || typeName.equals("boolean")) { fieldMap.putIfAbsent(fieldName, new Field(typeName, new Name(fieldName))); - }else{ + } else { fieldMap.putIfAbsent(fieldName, new Field(new Name(fieldName), typeName, null, true, typeName, false)); } Set annotationsSet = new HashSet<>(); - if(isLombok(analysisType)){ + if (isLombok(analysisType)) { ent = new Entity(new Name(clazz.getSimpleName())); } for (Annotation ann : field.getWrapped().getAnnotations()) { - if(ann.toString().startsWith(ENTITY_PACKAGE)){ - //Create new entity if it does not exist + if (ann.toString().startsWith(ENTITY_PACKAGE)) { + // Create new entity if it does not exist if (ent == null) { ent = new Entity(new Name(clazz.getSimpleName())); } - //Create a new annotation and set it's name + // Create a new annotation and set it's name com.oracle.svm.hosted.prophet.model.Annotation tempAnnot = new com.oracle.svm.hosted.prophet.model.Annotation(); String annName = ann.toString(); - //String manipulation for annotation names - if(annName.contains(ENTITY_PACKAGE)){ + // String manipulation for annotation names + if (annName.contains(ENTITY_PACKAGE)) { annName = annName.replace(ENTITY_PACKAGE, ""); annName = "@" + annName; annName = annName.substring(0, annName.indexOf("(")); } tempAnnot.setName(annName); - //Add it to the set + // Add it to the set annotationsSet.add(tempAnnot); } } - //Add the annotation set to the field and put it in the map + // Add the annotation set to the field and put it in the map Field updatedField = fieldMap.get(fieldName); updatedField.setAnnotations(annotationsSet); fieldMap.put(fieldName, updatedField); @@ -131,8 +112,8 @@ public static Optional extractClassEntityCalls(Class clazz, AnalysisM } } if (ent != null) { - //if (!fieldMap.values().isEmpty()) - ent.setFields(new HashSet<>(fieldMap.values())); + // if (!fieldMap.values().isEmpty()) + ent.setFields(new HashSet<>(fieldMap.values())); } return Optional.ofNullable(ent); @@ -143,31 +124,31 @@ public static Optional extractClassEntityCalls(Class clazz, AnalysisM return Optional.ofNullable(ent); } - //Because Lombok annotations are processed at compile-time, they are not retained in the compiled - //class' file annotation table - public static boolean isLombok(AnalysisType analysisType){ - - AnalysisField[] fields = analysisType.getInstanceFields(false); - AnalysisMethod[] methods = analysisType.getDeclaredMethods(); - boolean getFound, setFound; + // Because Lombok annotations are processed at compile-time, they are not retained in the + // compiled + // class' file annotation table + public static boolean isLombok(AnalysisType analysisType) { - for(AnalysisField field : fields){ + ResolvedJavaField[] fields = analysisType.getInstanceFields(false); + AnalysisMethod[] methods = ((AnalysisMethod[]) analysisType.getDeclaredMethods()); + boolean getFound, setFound; + for (ResolvedJavaField f : fields) { + AnalysisField field = (AnalysisField) f; getFound = false; setFound = false; - for(AnalysisMethod method : methods){ - if(method.getName().toLowerCase().equals("get" + field.getName().toLowerCase()) - || method.getName().toLowerCase().equals("is" + field.getName().toLowerCase())){ + for (AnalysisMethod method : methods) { + if (method.getName().toLowerCase().equals("get" + field.getName().toLowerCase()) || method.getName().toLowerCase().equals("is" + field.getName().toLowerCase())) { getFound = true; } - if(method.getName().toLowerCase().equals("set" + field.getName().toLowerCase())){ + if (method.getName().toLowerCase().equals("set" + field.getName().toLowerCase())) { setFound = true; } } - if(!(getFound && setFound)){ + if (!(getFound && setFound)) { return false; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/ProphetPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/ProphetPlugin.java index b725062638c8..743c77332d47 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/ProphetPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/ProphetPlugin.java @@ -4,19 +4,13 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Set; - -import javax.management.RuntimeErrorException; - import java.util.Map; +import java.util.Optional; import java.util.Set; import org.graalvm.compiler.options.Option; @@ -26,18 +20,11 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.analysis.Inflation; +import com.oracle.svm.hosted.prophet.model.Endpoint; import com.oracle.svm.hosted.prophet.model.Entity; -import com.oracle.svm.hosted.prophet.model.Field; import com.oracle.svm.hosted.prophet.model.Module; import com.oracle.svm.hosted.prophet.model.Name; -import java.util.*; -import java.util.Optional; - -import com.oracle.svm.hosted.prophet.model.Endpoint; import com.oracle.svm.hosted.prophet.model.RestCall; -import com.oracle.svm.hosted.prophet.RestDump; - -import com.oracle.svm.hosted.prophet.Logger; public class ProphetPlugin { @@ -95,9 +82,9 @@ public static void run(ImageClassLoader loader, AnalysisUniverse aUniverse, Anal String basePackage = Options.ProphetBasePackage.getValue(); String msName = Options.ProphetMicroserviceName.getValue(); - if (msName == null){ + if (msName == null) { throw new RuntimeException("ProphetMicroserviceName option was not provided"); - }else if (basePackage == null){ + } else if (basePackage == null) { throw new RuntimeException("ProphetMicroserviceName option was not provided"); } @@ -134,7 +121,7 @@ private static void dumpModule(Module module) { private Module doRun() { URL enumeration = loader.getClassLoader().getResource("application.yml"); - if (enumeration != null){ + if (enumeration != null) { try { this.propMap = new org.yaml.snakeyaml.Yaml().load(new FileReader(enumeration.getFile())); } catch (FileNotFoundException e) { @@ -153,28 +140,12 @@ private Module processClasses(List> classes) { logger.info("Amount of classes = " + classes.size()); for (Class clazz : classes) { - if (extractRestCalls) { - RestCallExtraction.extractClassRestCalls(clazz, metaAccess, bb); - EndpointExtraction.extractEndpoints(clazz, metaAccess, bb, this.propMap); - Annotation[] annotations = clazz.getAnnotations(); - for (Annotation ann : annotations) { - if (ann.annotationType().getName().startsWith("javax.persistence.Entity")) { - Entity entity = processEntity(clazz, ann); - entities.add(entity); - } - } - // add if class is entity Optional ent = EntityExtraction.extractClassEntityCalls(clazz, metaAccess, bb); ent.ifPresent(entities::add); Set restCalls = RestCallExtraction.extractClassRestCalls(clazz, metaAccess, bb, this.propMap, Options.ProphetMicroserviceName.getValue()); restCallList.addAll(restCalls); - if (extractRestCalls){ - EndpointExtraction.extractEndpoints(clazz, metaAccess, bb); - //RestCallExtraction.extractClassRestCalls(clazz, metaAccess, bb, this.propMap); - } - RestCallExtraction.extractClassRestCalls(clazz, metaAccess, bb, this.propMap); - //ENDPOINT EXTRACTION HERE + // ENDPOINT EXTRACTION HERE Set endpoints = EndpointExtraction.extractEndpoints(clazz, metaAccess, bb, Options.ProphetMicroserviceName.getValue()); endpointList.addAll(endpoints); @@ -182,40 +153,6 @@ private Module processClasses(List> classes) { return new Module(new Name(msName), entities, restCallList, endpointList); } - // private void dumpAllClasses() { - // logger.debug("---All app classes---"); - // allClasses.forEach(System.out::println); - // logger.debug("---------------------"); - // } - - private Set filterEntityClasses(List> classes) { - var entities = new HashSet(); - for (Class clazz : classes) { - Annotation[] annotations = clazz.getAnnotations(); - for (Annotation ann : annotations) { - if (ann.annotationType().getName().startsWith("javax.persistence.Entity")) { - Entity entity = processEntity(clazz, ann); - entities.add(entity); - } - } - } - return entities; - } - - // private Set filterEntityClasses(List> classes) { - // var entities = new HashSet(); - // for (Class clazz : classes) { - // Annotation[] annotations = clazz.getAnnotations(); - // for (Annotation ann : annotations) { - // if (ann.annotationType().getName().startsWith("javax.persistence.Entity")) { - // Entity entity = processEntity(clazz, ann); - // entities.add(entity); - // } - // } - // } - // return entities; - // } - private List> filterRelevantClasses() { var res = new ArrayList>(); for (Class applicationClass : allClasses) { @@ -224,13 +161,4 @@ private List> filterRelevantClasses() { } return res; } - - private List> filterClasses() { - var res = new ArrayList>(); - for (Class applicationClass : allClasses) { - if (applicationClass.getName().startsWith(basePackage)) - res.add(applicationClass); - } - return res; - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/RestCallExtraction.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/RestCallExtraction.java index da4808c3d145..290176a7b4f3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/RestCallExtraction.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/prophet/RestCallExtraction.java @@ -1,54 +1,39 @@ package com.oracle.svm.hosted.prophet; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.reachability.ReachabilityAnalysisMethod; -import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; -import com.oracle.svm.hosted.analysis.Inflation; - -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.PrimitiveConstant; - -import java.util.HashSet; -import java.util.Arrays; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodes.BeginNode; import org.graalvm.compiler.nodes.CallTargetNode; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.options.Option; import org.graalvm.compiler.nodes.java.LoadFieldNode; -import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; -import org.graalvm.compiler.nodes.InvokeWithExceptionNode; -import org.graalvm.compiler.nodes.PiNode; -import org.graalvm.compiler.nodes.BeginNode; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.lir.ConstantValue; -import org.graalvm.compiler.nodeinfo.Verbosity; import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.Optional; + +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.reachability.ReachabilityAnalysisMethod; +import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; +import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.prophet.model.RESTParameter; -import com.oracle.svm.hosted.prophet.model.Entity; import com.oracle.svm.hosted.prophet.model.RestCall; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; + public class RestCallExtraction { /* @@ -64,7 +49,7 @@ public class RestCallExtraction { public static Set extractClassRestCalls(Class clazz, AnalysisMetaAccess metaAccess, Inflation bb, Map propMap, String msName) { AnalysisType analysisType = metaAccess.lookupJavaType(clazz); try { - for (AnalysisMethod method : analysisType.getDeclaredMethods()) { + for (AnalysisMethod method : ((AnalysisMethod[]) analysisType.getDeclaredMethods())) { try { // if (!method.getQualifiedName().contains("getExams")){ // continue; @@ -375,8 +360,8 @@ private static String extractURI(CallTargetNode node, Map propMa // System.out.println("arg is a LOAD_FIELD_NODE, arg = " + arg); LoadFieldNode loadfieldNode = (LoadFieldNode) arg; AnalysisField field = (AnalysisField) loadfieldNode.field(); - - for (java.lang.annotation.Annotation annotation : field.getAnnotations()) { + + for (java.lang.annotation.Annotation annotation : field.getWrapped().getAnnotations()) { if (annotation.annotationType().getName().contains("Value")) { // System.out.println("Load field with value annotation"); // System.out.println("methods = " + annotation.annotationType().getMethods());