diff --git a/src/main/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethods.java b/src/main/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethods.java new file mode 100644 index 0000000000..f9b3f0508f --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethods.java @@ -0,0 +1,183 @@ +/* + * Copyright 2024 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.migrate; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.J; + +@Value +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class ReplaceComSunAWTUtilitiesMethods extends Recipe { + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.sun.awt.AWTUtilities isTranslucencySupported(com.sun.awt.AWTUtilities.Translucency)", + required = false) + String getAWTIsWindowsTranslucencyPattern; + + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilities isWindowOpaque(java.awt.Window)", + required = false) + String isWindowOpaquePattern; + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilities isTranslucencyCapable(java.awt.GraphicsConfiguration)", + required = false) + String isTranslucencyCapablePattern; + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilities setWindowOpacity(java.awt.Window, float)", + required = false) + String setWindowOpacityPattern; + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilities getWindowOpacity(java.awt.Window)", + required = false) + String getWindowOpacityPattern; + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilitiesTest getWindowShape(java.awt.Window)", + required = false) + String getWindowShapePattern; + + @Option(displayName = "Method pattern to replace", + description = "The method pattern to match and replace.", + example = "com.test.AWTUtilities setComponentMixingCutoutShape(java.awt.Component,java.awt.Shape)", + required = false) + String setComponentMixingCutoutShapePattern; + + @JsonCreator + public ReplaceComSunAWTUtilitiesMethods() { + getAWTIsWindowsTranslucencyPattern = "com.sun.awt.AWTUtilities isTranslucencySupported(com.sun.awt.AWTUtilities.Translucency)"; + getWindowOpacityPattern = "com.sun.awt.AWTUtilities getWindowOpacity(java.awt.Window)"; + getWindowShapePattern = "com.sun.awt.AWTUtilities getWindowShape(java.awt.Window)"; + isWindowOpaquePattern = "com.sun.awt.AWTUtilities isWindowOpaque(java.awt.Window)"; + isTranslucencyCapablePattern = "com.sun.awt.AWTUtilities isTranslucencyCapable(java.awt.GraphicsConfiguration)"; + setComponentMixingCutoutShapePattern = "com.sun.awt.AWTUtilities setComponentMixingCutoutShape(java.awt.Component,java.awt.Shape)"; + setWindowOpacityPattern = "com.sun.awt.AWTUtilities setWindowOpacity(java.awt.Window, float)"; + } + + @Override + public String getDisplayName() { + return "Replace `com.sun.awt.AWTUtilities` static method invocations"; + } + + @Override + public String getDescription() { + return "This recipe replaces several static calls in `com.sun.awt.AWTUtilities` with the JavaSE 11 equivalent. " + + "The methods replaced are `AWTUtilities.isTranslucencySupported()`, `AWTUtilities.setWindowOpacity()`, `AWTUtilities.getWindowOpacity()`, " + + "`AWTUtilities.getWindowShape()`, `AWTUtilities.isWindowOpaque()`, `AWTUtilities.isTranslucencyCapable()` and `AWTUtilities.setComponentMixingCutoutShape()`."; + } + + @Override + public TreeVisitor getVisitor() { + MethodMatcher getAWTIsWindowsTranslucencyMethod = new MethodMatcher(getAWTIsWindowsTranslucencyPattern); + MethodMatcher getWindowOpacityPatternMethod = new MethodMatcher(getWindowOpacityPattern); + MethodMatcher getWindowShapePatternMethod = new MethodMatcher(getWindowShapePattern); + MethodMatcher isWindowOpaquePatternMethod = new MethodMatcher(isWindowOpaquePattern); + MethodMatcher isTranslucencyCapablePatternMethod = new MethodMatcher(isTranslucencyCapablePattern); + MethodMatcher setComponentMixingCutoutShapePatternMethod = new MethodMatcher(setComponentMixingCutoutShapePattern); + MethodMatcher setWindowOpacityPatternMethod = new MethodMatcher(setWindowOpacityPattern); + + return new JavaVisitor() { + @Override + public J visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) { + super.visitMethodInvocation(mi, ctx); + if (getAWTIsWindowsTranslucencyMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + maybeAddImport("java.awt.GraphicsDevice", false); + maybeAddImport("java.awt.GraphicsEnvironment", false); + maybeAddImport("java.awt.Window", false); + maybeAddImport("java.awt.GraphicsDevice.WindowTranslucency", false); + String templateString = "GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isWindowTranslucencySupported(WindowTranslucency." + + ((J.FieldAccess) mi.getArguments().get(0)).getSimpleName(); + return JavaTemplate.builder(templateString). + imports("java.awt.GraphicsDevice", + "java.awt.GraphicsEnvironment", + "java.awt.Window", + "java.awt.GraphicsDevice.WindowTranslucency") + .build() + .apply(getCursor(), mi.getCoordinates().replace()) + .withPrefix(mi.getPrefix()); + } + if (isWindowOpaquePatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.isOpaque()") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0)) + .withPrefix(mi.getPrefix()); + } + if (isTranslucencyCapablePatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.isTranslucencyCapable()") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0)) + .withPrefix(mi.getPrefix()); + } + if (setWindowOpacityPatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.setOpacity(#{any()})") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), + mi.getArguments().get(0), + mi.getArguments().get(1)) + .withPrefix(mi.getPrefix()); + } + if (getWindowOpacityPatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.getOpacity()") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0)) + .withPrefix(mi.getPrefix()); + } + if (getWindowShapePatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.getShape()") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), mi.getArguments().get(0)) + .withPrefix(mi.getPrefix()); + } + if (setComponentMixingCutoutShapePatternMethod.matches(mi)) { + maybeRemoveImport(mi.getMethodType().getDeclaringType().getFullyQualifiedName()); + return JavaTemplate.builder("#{any()}.setMixingCutoutShape(#{any()})") + .build() + .apply(getCursor(), mi.getCoordinates().replace(), + mi.getArguments().get(0), + mi.getArguments().get(1)) + .withPrefix(mi.getPrefix()); + } + return mi; + } + }; + } +} diff --git a/src/main/java/org/openrewrite/java/migrate/ReplaceLocalizedStreamMethods.java b/src/main/java/org/openrewrite/java/migrate/ReplaceLocalizedStreamMethods.java index 1669daf9f4..0ba027061a 100644 --- a/src/main/java/org/openrewrite/java/migrate/ReplaceLocalizedStreamMethods.java +++ b/src/main/java/org/openrewrite/java/migrate/ReplaceLocalizedStreamMethods.java @@ -33,12 +33,14 @@ public class ReplaceLocalizedStreamMethods extends Recipe { @Option(displayName = "Method pattern to replace", description = "The method pattern to match and replace.", - example = "java.lang.Runtime getLocalizedInputStream(java.io.InputStream)") + example = "java.lang.Runtime getLocalizedInputStream(java.io.InputStream)", + required = false) String localizedInputStreamMethodMatcher; @Option(displayName = "Method pattern to replace", description = "The method pattern to match and replace.", - example = "java.lang.Runtime getLocalizedOutputStream(java.io.OutputStream)") + example = "java.lang.Runtime getLocalizedOutputStream(java.io.OutputStream)", + required = false) String localizedOutputStreamMethodMatcher; @JsonCreator diff --git a/src/main/resources/META-INF/rewrite/java-version-11.yml b/src/main/resources/META-INF/rewrite/java-version-11.yml index eb3e7cf90f..f8b23c51f6 100644 --- a/src/main/resources/META-INF/rewrite/java-version-11.yml +++ b/src/main/resources/META-INF/rewrite/java-version-11.yml @@ -73,8 +73,8 @@ recipeList: getPeerMethodPattern: java.awt.* getPeer() lightweightPeerFQCN: java.awt.peer.LightweightPeer - org.openrewrite.scala.migrate.UpgradeScala_2_12 + - org.openrewrite.java.migrate.ReplaceComSunAWTUtilitiesMethods - org.openrewrite.java.migrate.ReplaceLocalizedStreamMethods - --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.migrate.UpgradeBuildToJava11 @@ -290,3 +290,4 @@ recipeList: - org.openrewrite.java.ChangeMethodName: methodPattern: java.nio.file.Path get(..) newMethodName: of + diff --git a/src/test/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethodsTest.java b/src/test/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethodsTest.java new file mode 100644 index 0000000000..d20b9bc8e5 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/ReplaceComSunAWTUtilitiesMethodsTest.java @@ -0,0 +1,171 @@ +/* + * Copyright 2024 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.migrate; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ReplaceComSunAWTUtilitiesMethodsTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new ReplaceComSunAWTUtilitiesMethods( + "com.test.AWTUtilitiesTest isTranslucencySupported1(com.test.AWTUtilitiesTest.Translucency)", + "com.test.AWTUtilitiesTest isWindowOpaque(java.awt.Window)", + "com.test.AWTUtilitiesTest isTranslucencyCapable(java.awt.GraphicsConfiguration)", + "com.test.AWTUtilitiesTest setWindowOpacity(java.awt.Window,float)", + "com.test.AWTUtilitiesTest getWindowOpacity(java.awt.Window)", + "com.test.AWTUtilitiesTest getWindowShape(java.awt.Window)", + "com.test.AWTUtilitiesTest setComponentMixingCutoutShape(java.awt.Component,java.awt.Shape)")) + .parser(JavaParser.fromJavaVersion() + //language=java + .dependsOn( + """ + package com.test; + + import java.awt.Window; + import java.awt.GraphicsConfiguration; + import java.awt.Shape; + import java.awt.Component; + + public class AWTUtilitiesTest { + private static final String TRANSLUCENT = "test"; + public enum Translucency { + PERPIXEL_TRANSPARENT, + TRANSLUCENT, + PERPIXEL_TRANSLUCENT; + } + public static boolean isTranslucencySupported1(Translucency translucencyKind) { + return true; + } + public static boolean isWindowOpaque(Window win) { + return true; + } + public static boolean isTranslucencyCapable(GraphicsConfiguration gc) { + return true; + } + public static void setWindowOpacity(Window win,float f) { + + } + public static float getWindowOpacity(Window win) { + return 1; + } + public static Shape getWindowShape(Window win) { + return null; + } + public static void setComponentMixingCutoutShape(Component c, Shape sh){ + + } + } + """ + ) + ); + } + + @Test + void replaceComSunAWTUtilitiesClassesIsTranslucencySupported() { + rewriteRun( + //language=java + java( + """ + import com.test.AWTUtilitiesTest; + + class Test { + void foo() { + boolean f = AWTUtilitiesTest.isTranslucencySupported1(AWTUtilitiesTest.Translucency.TRANSLUCENT); + boolean j = AWTUtilitiesTest.isTranslucencySupported1(AWTUtilitiesTest.Translucency.PERPIXEL_TRANSPARENT); + boolean k = AWTUtilitiesTest.isTranslucencySupported1(AWTUtilitiesTest.Translucency.PERPIXEL_TRANSLUCENT); + } + } + """, + """ + import java.awt.GraphicsDevice; + import java.awt.GraphicsDevice.WindowTranslucency; + import java.awt.GraphicsEnvironment; + import java.awt.Window; + + class Test { + void foo() { + boolean f = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isWindowTranslucencySupported(WindowTranslucency.TRANSLUCENT); + boolean j = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSPARENT); + boolean k = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isWindowTranslucencySupported(WindowTranslucency.PERPIXEL_TRANSLUCENT); + } + } + """ + ) + ); + } + + @Test + @DocumentExample + void replaceComSunAWTUtilitiesClassesRemaining() { + rewriteRun( + //language=java + java( + """ + package com.test; + import com.test.AWTUtilitiesTest; + import java.awt.Window; + import java.awt.*; + import javax.swing.*; + import java.awt.geom.Ellipse2D; + + class Test { + void foo() { + Window win = new Window(new JFrame("test")); + boolean f = AWTUtilitiesTest.isWindowOpaque(win); + AWTUtilitiesTest.setWindowOpacity(win,1); + float l = AWTUtilitiesTest.getWindowOpacity(win); + Shape sh = AWTUtilitiesTest.getWindowShape(win); + GraphicsConfiguration gc = null; + boolean f = AWTUtilitiesTest.isTranslucencyCapable(gc); + Component c = null; + Shape sh = new Ellipse2D.Double(0, 0, c.getWidth(), c.getHeight()); + AWTUtilitiesTest.setComponentMixingCutoutShape(c, sh); + } + } + """, + """ + package com.test; + import java.awt.Window; + import java.awt.*; + import javax.swing.*; + import java.awt.geom.Ellipse2D; + + class Test { + void foo() { + Window win = new Window(new JFrame("test")); + boolean f = win.isOpaque(); + win.setOpacity(1); + float l = win.getOpacity(); + Shape sh = win.getShape(); + GraphicsConfiguration gc = null; + boolean f = gc.isTranslucencyCapable(); + Component c = null; + Shape sh = new Ellipse2D.Double(0, 0, c.getWidth(), c.getHeight()); + c.setMixingCutoutShape(sh); + } + } + """ + ) + ); + } +}