From 4fdf5e5af0e8c5213646d02db850efcf1e848962 Mon Sep 17 00:00:00 2001 From: Juan Manuel Leflet Estrada Date: Mon, 22 Jul 2024 16:33:23 +0200 Subject: [PATCH] :bug: Add annotation inspection support (#659) This PR adds support for inspecting annotations. :green_circle: Things that can be done now: - Check for annotations that are annotating specific `FIELD_DECLARATION`, `METHOD_DECLARATION` or `TYPE` - Match against `METHOD_DECLARATION` :red_circle: Things that cannot be done **yet**: - Match `location: ANNOTATION` and inspect its values. - Inspect on annotations on `location: CONSTRUCTOR`. Depends on: - https://github.com/konveyor/java-analyzer-bundle/pull/104 Fixes: - https://github.com/konveyor/analyzer-lsp/issues/460 - https://github.com/konveyor/analyzer-lsp/issues/467 --------- Signed-off-by: Juan Manuel Leflet Estrada --- demo-output.yaml | 42 +++++++++++++++++++ .../pkg/java_external_provider/provider.go | 17 +++++++- .../java_external_provider/service_client.go | 11 ++++- rule-example.yaml | 37 ++++++++++++++++ 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/demo-output.yaml b/demo-output.yaml index fd1953b9..bdbbe45a 100644 --- a/demo-output.yaml +++ b/demo-output.yaml @@ -912,6 +912,48 @@ kind: Field name: repository package: io.konveyor.demo.ordermanagement.service + java-annotation-inspection-01: + description: | + This rule looks for a given class annotated with a given annotation + category: mandatory + incidents: + - uri: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/config/PersistenceConfig.java + message: Annotation instpection 01 + codeSnip: "17 import org.springframework.transaction.annotation.EnableTransactionManagement;\n18 \n19 import io.konveyor.demo.config.ApplicationConfiguration;\n20 \n21 @Configuration\n22 @EnableJpaRepositories(basePackages = {\n23 \"io.konveyor.demo.ordermanagement.repository\"\n24 })\n25 @EnableTransactionManagement\n26 @EnableSpringDataWebSupport\n27 public class PersistenceConfig {\n28 \n29 \n30 \t@Bean\n31 public LocalContainerEntityManagerFactoryBean entityManagerFactory() {\n32 final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();\n33 em.setDataSource(dataSource());\n34 em.setPackagesToScan(\"io.konveyor.demo.ordermanagement.model\");\n35 em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());\n36 em.setJpaProperties(additionalProperties());\n37 " + lineNumber: 27 + variables: + file: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/config/PersistenceConfig.java + kind: Class + name: PersistenceConfig + package: io.konveyor.demo.ordermanagement.config + java-annotation-inspection-02: + description: | + This rule looks for a given method annotated with a given annotation + category: mandatory + incidents: + - uri: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/config/PersistenceConfig.java + message: Annotation instpection 02 + codeSnip: "46 dataSource.setUrl(config.getProperty(\"jdbc.url\"));\n47 dataSource.setUsername(config.getProperty(\"jdbc.user\"));\n48 dataSource.setPassword(config.getProperty(\"jdbc.password\"));\n49 \n50 return dataSource;\n51 }\n52 \n53 @Bean\n54 public PlatformTransactionManager transactionManager() {\n55 final JpaTransactionManager transactionManager = new JpaTransactionManager();\n56 transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());\n57 return transactionManager;\n58 }\n59 \n60 @Bean\n61 public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {\n62 return new PersistenceExceptionTranslationPostProcessor();\n63 }\n64 \n65 final Properties additionalProperties() {\n66 \tApplicationConfiguration config = new ApplicationConfiguration();" + lineNumber: 56 + variables: + file: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/config/PersistenceConfig.java + kind: Method + name: transactionManager + package: io.konveyor.demo.ordermanagement.config + java-annotation-inspection-03: + description: | + This rule looks for a given field annotated with a given annotation + category: mandatory + incidents: + - uri: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/controller/CustomerController.java + message: Annotation instpection 03 + codeSnip: "11 import org.springframework.web.bind.annotation.GetMapping;\n12 import org.springframework.web.bind.annotation.PathVariable;\n13 import org.springframework.web.bind.annotation.RequestMapping;\n14 import org.springframework.web.bind.annotation.RestController;\n15 \n16 @RestController\n17 @RequestMapping(\"/customers\")\n18 public class CustomerController {\n19 \t\n20 \t@Autowired\n21 \tprivate CustomerService customerService;\n22 \t\n23 \tprivate static Logger logger = Logger.getLogger( CustomerController.class.getName() );\n24 \t\n25 \t@GetMapping(value = \"/{id}\", produces = MediaType.APPLICATION_JSON_VALUE)\n26 public Customer getById(@PathVariable(\"id\") Long id) {\n27 \t\tCustomer c = customerService.findById(id);\n28 \t\tif (c == null) {\n29 \t\t\tthrow new ResourceNotFoundException(\"Requested order doesn't exist\");\n30 \t\t}\n31 \t\tlogger.debug(\"Returning element: \" + c);" + lineNumber: 21 + variables: + file: file:///examples/customers-tomcat-legacy/src/main/java/io/konveyor/demo/ordermanagement/controller/CustomerController.java + kind: Field + name: customerService + package: io.konveyor.demo.ordermanagement.controller java-downloaded-maven-artifact: description: | This rule tests the application downloaded from maven artifact diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index bfa5ac8d..4519fbd7 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -60,6 +60,7 @@ var locationToCode = map[string]int{ "type": 10, "package": 11, "field": 12, + "method": 13, } type javaProvider struct { @@ -86,8 +87,19 @@ type javaCondition struct { } type referenceCondition struct { - Pattern string `yaml:"pattern"` - Location string `yaml:"location"` + Pattern string `yaml:"pattern"` + Location string `yaml:"location"` + Annotated annotated `yaml:"annotated,omitempty" json:"annotated,omitempty"` +} + +type annotated struct { + Pattern string `yaml:"pattern" json:"pattern"` + Elements []element `yaml:"elements,omitempty" json:"elements,omitempty"` +} + +type element struct { + Name string `yaml:"name" json:"name"` + Value string `yaml:"value" json:"value"` // can be a (java) regex pattern } func NewJavaProvider(log logr.Logger, lspServerName string, contextLines int) *javaProvider { @@ -296,6 +308,7 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide "-Djava.net.useSystemProxies=true", "-configuration", "./", + //"--jvm-arg=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:1044", "-data", workspace, } diff --git a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go index eb57a858..b26f7b45 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "regexp" "strings" "sync" @@ -54,7 +55,7 @@ func (p *javaServiceClient) Evaluate(ctx context.Context, cap string, conditionI if cond.Referenced.Pattern == "" { return provider.ProviderEvaluateResponse{}, fmt.Errorf("provided query pattern empty") } - symbols, err := p.GetAllSymbols(ctx, cond.Referenced.Pattern, cond.Referenced.Location) + symbols, err := p.GetAllSymbols(ctx, cond.Referenced.Pattern, cond.Referenced.Location, cond.Referenced.Annotated) if err != nil { p.log.Error(err, "unable to get symbols", "symbols", symbols, "cap", cap, "conditionInfo", cond) return provider.ProviderEvaluateResponse{}, err @@ -86,6 +87,8 @@ func (p *javaServiceClient) Evaluate(ctx context.Context, cap string, conditionI incidents, err = p.filterDefault(symbols) case 12: incidents, err = p.filterDefault(symbols) + case 13: + incidents, err = p.filterDefault(symbols) default: } @@ -105,7 +108,7 @@ func (p *javaServiceClient) Evaluate(ctx context.Context, cap string, conditionI }, nil } -func (p *javaServiceClient) GetAllSymbols(ctx context.Context, query, location string) ([]protocol.WorkspaceSymbol, error) { +func (p *javaServiceClient) GetAllSymbols(ctx context.Context, query, location string, annotation annotated) ([]protocol.WorkspaceSymbol, error) { // This command will run the added bundle to the language server. The command over the wire needs too look like this. // in this case the project is hardcoded in the init of the Langauge Server above // workspace/executeCommand '{"command": "io.konveyor.tackle.ruleEntry", "arguments": {"query":"*customresourcedefinition","project": "java"}}' @@ -116,6 +119,10 @@ func (p *javaServiceClient) GetAllSymbols(ctx context.Context, query, location s "analysisMode": string(p.config.AnalysisMode), } + if !reflect.DeepEqual(annotation, annotated{}) { + argumentsMap["annotationQuery"] = annotation + } + if p.includedPaths != nil && len(p.includedPaths) > 0 { argumentsMap[provider.IncludedPathsConfigKey] = p.includedPaths p.log.V(5).Info("setting search scope by filepaths", "paths", p.includedPaths) diff --git a/rule-example.yaml b/rule-example.yaml index 542f0234..c67a94dc 100644 --- a/rule-example.yaml +++ b/rule-example.yaml @@ -338,3 +338,40 @@ java.referenced: pattern: io.konveyor.demo.ordermanagement.repository.CustomerRepository location: FIELD + +- category: mandatory + description: | + This rule looks for a given class annotated with a given annotation + message: "Annotation instpection 01" + ruleID: java-annotation-inspection-01 + when: + java.referenced: + pattern: io.konveyor.demo.ordermanagement.config.PersistenceConfig + location: TYPE + annotated: + pattern: org.springframework.data.jpa.repository.config.EnableJpaRepositories + elements: + - name: basePackages + value: "io.konveyor.demo.ordermanagement.repository" +- category: mandatory + description: | + This rule looks for a given method annotated with a given annotation + message: "Annotation instpection 02" + ruleID: java-annotation-inspection-02 + when: + java.referenced: + pattern: entityManagerFactory() + location: METHOD_DECLARATION + annotated: + pattern: org.springframework.context.annotation.Bean +- category: mandatory + description: | + This rule looks for a given field annotated with a given annotation + message: "Annotation instpection 03" + ruleID: java-annotation-inspection-03 + when: + java.referenced: + pattern: io.konveyor.demo.ordermanagement.service.CustomerService + location: FIELD + annotated: + pattern: org.springframework.beans.factory.annotation.Autowired