All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrewrite.java.spring.boot2.ConditionalOnBeanAnyNestedCondition Maven / Gradle / Ivy

Go to download

Eliminate legacy Spring patterns and migrate between major Spring Boot versions. Automatically.

There is a newer version: 5.19.0
Show newest version
/*
 * Copyright 2021 the original author or authors.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openrewrite.java.spring.boot2; import org.openrewrite.*; import org.openrewrite.java.AnnotationMatcher; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.Statement; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; public class ConditionalOnBeanAnyNestedCondition extends Recipe { @Override public String getDisplayName() { return "Migrate multi-condition `@ConditionalOnBean` annotations"; } @Override public String getDescription() { return "Migrate multi-condition `@ConditionalOnBean` annotations to `AnyNestedCondition`."; } @Override public TreeVisitor getVisitor() { return Preconditions.check(new UsesType<>("org.springframework.boot.autoconfigure.condition.ConditionalOnBean", false), new ConditionalOnBeanAnyNestedConditionVisitor()); } private static class ConditionalOnBeanAnyNestedConditionVisitor extends JavaIsoVisitor { private static final String ANY_CONDITION_TEMPLATES = "any_condition_templates"; private static final AnnotationMatcher CONDITIONAL_BEAN = new AnnotationMatcher("@org.springframework.boot.autoconfigure.condition.ConditionalOnBean"); @Override public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { J.Annotation a = super.visitAnnotation(annotation, ctx); if (CONDITIONAL_BEAN.matches(a) && a.getArguments() != null) { // First check for an array of Class arguments List conditionalOnBeanCandidates = new ArrayList<>(); for (Expression p : a.getArguments()) { if (p instanceof J.NewArray) { J.NewArray na = (J.NewArray) p; if (na.getInitializer() != null && na.getInitializer().size() > 1) { for (Expression expression : na.getInitializer()) { J.FieldAccess fieldAccess = (J.FieldAccess) expression; Expression target = fieldAccess.getTarget(); if (target instanceof J.Identifier) { J.Identifier identifier = (J.Identifier) target; String simpleName = identifier.getSimpleName(); conditionalOnBeanCandidates.add(simpleName); } } } } } String nestedConditionParameterFormat = "%s.class"; // If class arguments are not found then search for an array of type arguments if (conditionalOnBeanCandidates.isEmpty()) { for (Expression arg : a.getArguments()) { if (arg instanceof J.Assignment && ((J.Assignment) arg).getAssignment() instanceof J.NewArray && "type".equals(((J.Identifier) ((J.Assignment) arg).getVariable()).getSimpleName())) { J.NewArray na = (J.NewArray) ((J.Assignment) arg).getAssignment(); if (na.getInitializer() != null) { for (Expression l : na.getInitializer()) { J.Literal lit = (J.Literal) l; if (lit.getValue() != null) { conditionalOnBeanCandidates.add(lit.getValue().toString()); } } } } } nestedConditionParameterFormat = "type = \"%s\""; } if (!conditionalOnBeanCandidates.isEmpty()) { String conditionalClassName = conditionalClassNameFromCandidates(conditionalOnBeanCandidates); // Replacing the annotation will be performed by the JavaTemplate. // The associated conditional class must exist for the JavaTemplate to generate a type attributed AST boolean anyConditionClassExists = false; for (Statement statement : getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class).getBody().getStatements()) { if (statement instanceof J.ClassDeclaration) { J.ClassDeclaration c = (J.ClassDeclaration) statement; if (c.getSimpleName().equals(conditionalClassName)) { anyConditionClassExists = true; break; } } } if (anyConditionClassExists) { a = JavaTemplate.builder("@Conditional(#{}.class)") .imports("org.springframework.context.annotation.Conditional") .javaParser(JavaParser.fromJavaVersion() .classpathFromResources(ctx, "spring-context-5.*", "spring-boot-autoconfigure-2.*")) .build() .apply( getCursor(), a.getCoordinates().replace(), conditionalClassName ); maybeAddImport("org.springframework.context.annotation.Conditional"); } else { // add the new conditional class template string to the parent ClassDeclaration Cursor Cursor classDeclarationCursor = getCursor().dropParentUntil(it -> it instanceof J.ClassDeclaration || it == Cursor.ROOT_VALUE); Set anyConditionClasses = classDeclarationCursor.getMessage(ANY_CONDITION_TEMPLATES); if (anyConditionClasses == null) { anyConditionClasses = new TreeSet<>(); classDeclarationCursor.putMessage(ANY_CONDITION_TEMPLATES, anyConditionClasses); } anyConditionClasses.add(anyConditionClassTemplate(conditionalOnBeanCandidates, nestedConditionParameterFormat)); } } } return a; } @Override public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); Set conditionalTemplates = getCursor().pollMessage(ANY_CONDITION_TEMPLATES); if (conditionalTemplates != null && !conditionalTemplates.isEmpty()) { for (String s : conditionalTemplates) { JavaTemplate t = JavaTemplate.builder(s) .contextSensitive() .imports("org.springframework.boot.autoconfigure.condition.AnyNestedCondition") .javaParser(JavaParser.fromJavaVersion() .classpathFromResources(ctx, "spring-context-5.*", "spring-boot-autoconfigure-2.*")) .build(); c = maybeAutoFormat( c, t.apply(getCursor(), c.getBody().getCoordinates().lastStatement()), ctx); updateCursor(c); } // Schedule another visit to modify the associated annotations now that the new conditional classes have been added to the AST doAfterVisit(new ConditionalOnBeanAnyNestedConditionVisitor()); maybeAddImport("org.springframework.boot.autoconfigure.condition.AnyNestedCondition"); } return c; } private String conditionalClassNameFromCandidates(List conditionalCandidates) { return "Condition" + conditionalCandidates.stream().sorted().map(this::getSimpleName).collect(Collectors.joining("Or")); } private String anyConditionClassTemplate(List conditionalIdentifiers, String parameterFormatString) { String conditionalClassFormat = "@ConditionalOnBean(" + parameterFormatString + ")class %sCondition {}"; String conditionClassName = conditionalClassNameFromCandidates(conditionalIdentifiers); StringBuilder s = new StringBuilder("private static class ").append(conditionClassName) .append(" extends AnyNestedCondition {") .append(conditionClassName).append("(){super(ConfigurationPhase.REGISTER_BEAN);}"); conditionalIdentifiers.stream().sorted().forEach(ci -> s.append(String.format(conditionalClassFormat, ci, getSimpleName(ci)))); s.append("}"); return s.toString(); } private String getSimpleName(String type) { String t = type; if (t.endsWith(".class")) { t = t.substring(0, t.lastIndexOf(".")); } if (t.contains(".")) { t = t.substring(t.lastIndexOf(".") + 1); } return t; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy