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

org.openrewrite.staticanalysis.ExternalizableHasNoArgsConstructor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 the original author or authors.
 * 

* Licensed under the Moderne Source Available License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://docs.moderne.io/licensing/moderne-source-available-license *

* 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.staticanalysis; import org.openrewrite.ExecutionContext; import org.openrewrite.Preconditions; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.Statement; import org.openrewrite.java.tree.TypeUtils; import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.Set; public class ExternalizableHasNoArgsConstructor extends Recipe { private static final JavaType EXTERNALIZABLE_TYPE = JavaType.buildType("java.io.Externalizable"); @Override public String getDisplayName() { return "`Externalizable` classes have no-arguments constructor"; } @Override public String getDescription() { return "`Externalizable` classes handle both serialization and deserialization and must have a no-args constructor for the deserialization process."; } @Override public Duration getEstimatedEffortPerOccurrence() { return Duration.ofMinutes(20); } @Override public Set getTags() { return Collections.singleton("RSPEC-S2060"); } @Override public TreeVisitor getVisitor() { return Preconditions.check(new UsesType<>("java.io.Externalizable", false), new JavaIsoVisitor() { @Override public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx); if (TypeUtils.isAssignableTo(EXTERNALIZABLE_TYPE, cd.getType())) { boolean hasFinalUninitializedFieldVar = false; Integer firstMethodDeclarationIndex = null; List statements = cd.getBody().getStatements(); for (int i = 0; i < statements.size(); i++) { Statement statement = statements.get(i); if (statement instanceof J.VariableDeclarations) { J.VariableDeclarations varDecls = (J.VariableDeclarations) statement; if (J.Modifier.hasModifier(varDecls.getModifiers(), J.Modifier.Type.Final) && varDecls.getVariables().stream().anyMatch(v -> v.getInitializer() == null)) { hasFinalUninitializedFieldVar = true; break; } } // The new no-args constructor should be the first methodDeclaration if (statement instanceof J.MethodDeclaration && firstMethodDeclarationIndex == null) { firstMethodDeclarationIndex = i; } } if (!hasFinalUninitializedFieldVar && !hasNoArgsConstructor(cd) && parentClassHasNoArgsConstructor(cd)) { cd = JavaTemplate.builder("public " + cd.getSimpleName() + "() {}") .contextSensitive() .build() .apply(updateCursor(cd), cd.getBody().getCoordinates().lastStatement()); if (firstMethodDeclarationIndex != null) { statements.add(firstMethodDeclarationIndex, cd.getBody().getStatements().remove(cd.getBody().getStatements().size() - 1)); cd = cd.withBody(cd.getBody().withStatements(statements)); } } } return cd; } private boolean hasNoArgsConstructor(J.ClassDeclaration cd) { boolean hasNoArgsConstructor = false; boolean hasDefaultConstructor = true; for (Statement statement : cd.getBody().getStatements()) { if (statement instanceof J.MethodDeclaration) { J.MethodDeclaration md = (J.MethodDeclaration) statement; if (md.isConstructor()) { if (md.getParameters().isEmpty() || md.getParameters().get(0) instanceof J.Empty) { hasNoArgsConstructor = true; } else { hasDefaultConstructor = false; } } } } return hasDefaultConstructor || hasNoArgsConstructor; } private boolean parentClassHasNoArgsConstructor(J.ClassDeclaration cd) { if (cd.getExtends() == null) { return true; } JavaType.FullyQualified parentFq = TypeUtils.asFullyQualified(cd.getExtends().getType()); if (parentFq == null) { return false; } boolean hasNoArgsConstructor = false; boolean hasDefaultConstructor = true; for (JavaType.Method method : parentFq.getMethods()) { if ("".equals(method.getName())) { if (method.getParameterNames().isEmpty()) { hasNoArgsConstructor = true; } else { hasDefaultConstructor = false; } } } return hasDefaultConstructor || hasNoArgsConstructor; } }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy