Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.migrate;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.ChangeType;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class ArrayStoreExceptionToTypeNotPresentException extends Recipe {
@Override
public String getDisplayName() {
return "ArrayStoreExceptionToTypeNotPresentException";
}

@Override
public String getDescription() {
return "This recipe replaces catch blocks for ArrayStoreException around getAnnotation() with TypeNotPresentException to ensure compatibility with Java 11+.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
final MethodMatcher classGetAnnotationMethod = new MethodMatcher("java.lang.Class getAnnotation(java.lang.Class)");
return new JavaVisitor<ExecutionContext>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a Precondition here to only call the visitor when classGetAnnotationMethod is used. That way we can reject the vast majority of classes without visiting any elements, for a nice performance boost.


@Override
public J visitTry(J.Try tryStmt, ExecutionContext ctx) {
boolean flag = false;
if (containsGetAnnotation(tryStmt)) {
List<J.Try.Catch> updatedCatches = new ArrayList<>();
for (J.Try.Catch catchClause : tryStmt.getCatches()) {
if (catchClause.getParameter().getType() != null && catchClause.getParameter().getType().isAssignableFrom(Pattern.compile("java.lang.ArrayStoreException"))) {
J.Try.Catch updatedCatch = (J.Try.Catch) new ChangeType("java.lang.ArrayStoreException", "java.lang.TypeNotPresentException", true).getVisitor().visit(catchClause, ctx);
updatedCatches.add(updatedCatch);
flag = true;
} else {
updatedCatches.add(catchClause);
}
}
if (flag)
tryStmt = tryStmt.withCatches(updatedCatches);
}
return super.visitTry(tryStmt, ctx);
}

private boolean containsGetAnnotation(J.Try tryStmt) {
return tryStmt.getBody().getStatements().stream()
.filter(Expression.class::isInstance)
.map(Expression.class::cast)
.anyMatch(classGetAnnotationMethod::matches);
}
};
}
}

2 changes: 2 additions & 0 deletions src/main/resources/META-INF/rewrite/java-version-11.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ recipeList:
- org.openrewrite.scala.migrate.UpgradeScala_2_12
- org.openrewrite.java.migrate.ReplaceComSunAWTUtilitiesMethods
- org.openrewrite.java.migrate.ReplaceLocalizedStreamMethods
- org.openrewrite.java.migrate.ArrayStoreExceptionToTypeNotPresentException

---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.UpgradeBuildToJava11
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.migrate;

import org.junit.jupiter.api.Test;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.java;

public class TypeNotPresentExceptionTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new ArrayStoreExceptionToTypeNotPresentException());
}

@Test
void ArrayStoreExceptionTest() {
rewriteRun(
//language=java
java(
"""
import java.lang.annotation.*;
import java.util.*;

public class Test {
public void testMethod() {
try {
Object o = "test";
o.getClass().getAnnotation(Override.class);
} catch (ArrayStoreException e) {
System.out.println("Caught Exception");
}
try {
Object.class.getAnnotation(Override.class);
} catch (ArrayStoreException e) {
System.out.println("Caught ArrayStoreException");
}
}
}
""",
"""
import java.lang.annotation.*;
import java.util.*;

public class Test {
public void testMethod() {
try {
Object o = "test";
o.getClass().getAnnotation(Override.class);
} catch (TypeNotPresentException e) {
System.out.println("Caught Exception");
}
try {
Object.class.getAnnotation(Override.class);
} catch (TypeNotPresentException e) {
System.out.println("Caught ArrayStoreException");
}
}
}
"""
)
);
}

@Test
void rOtherExceptionsTest() {
rewriteRun(
//language=java
java(
"""
public class Test {
public void testMethod() {
try {
Object o = "test";
o.getClass().getAnnotation(Override.class);
} catch (NullPointerException e) {
System.out.println("Caught Exception");
}
}
}
"""
)
);
}
}