Skip to content

Support static imports when replacing JAX/RS MediaType #755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import javax.ws.rs.core.MediaType;
import java.util.stream.Collectors;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON;

@Path("/")
public class PersonController {

Expand All @@ -18,8 +20,8 @@ public String getHelloWorldJSON(@PathParam("name") String name) throws Exception

@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
public String getAllPersons(@QueryParam("q") String searchBy, @DefaultValue("0") @QueryParam("page") int page) throws Exception {
return "{\"message\":\"No person here...\"";
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2023 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.springframework.sbm.java.migration.recipes.openrewrite;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;

@Value
@EqualsAndHashCode(callSuper = false)
// TODO: Remove this class and use the one in Openrewrite core once we use 7.39.1 or later
public class ReplaceConstantWithAnotherConstant extends Recipe {

@Option(displayName = "Fully qualified name of the constant to replace", example = "org.springframework.http.MediaType.APPLICATION_JSON_VALUE")
String existingFullyQualifiedConstantName;

@Option(displayName = "Fully qualified name of the constant to use in place of existing constant", example = "org.springframework.http.MediaType.APPLICATION_JSON_VALUE")
String fullyQualifiedConstantName;

@Override
public String getDisplayName() {
return "Replace constant with another constant";
}

@Override
public String getDescription() {
return "Replace constant with another constant, adding/removing import on class if needed.";
}

@Override
protected TreeVisitor<?, ExecutionContext> getSingleSourceApplicableTest() {
return new UsesType<>(existingFullyQualifiedConstantName.substring(0,existingFullyQualifiedConstantName.lastIndexOf('.')));
}

@Override
public JavaVisitor<ExecutionContext> getVisitor() {
return new ReplaceConstantWithAnotherConstantVisitor(existingFullyQualifiedConstantName, fullyQualifiedConstantName);
}

private static class ReplaceConstantWithAnotherConstantVisitor extends JavaVisitor<ExecutionContext> {

private final String existingOwningType;
private final String constantName;
private final String owningType;
private final String template;

public ReplaceConstantWithAnotherConstantVisitor(String existingFullyQualifiedConstantName, String fullyQualifiedConstantName) {
this.existingOwningType = existingFullyQualifiedConstantName.substring(0, existingFullyQualifiedConstantName.lastIndexOf('.'));
this.constantName = existingFullyQualifiedConstantName.substring(existingFullyQualifiedConstantName.lastIndexOf('.') + 1);
this.owningType = fullyQualifiedConstantName.substring(0, fullyQualifiedConstantName.lastIndexOf('.'));
this.template = fullyQualifiedConstantName.substring(owningType.lastIndexOf('.') + 1);
}

@Override
public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext executionContext) {
if (isConstant(fieldAccess.getName().getFieldType())) {
maybeRemoveImport(existingOwningType);
if (existingOwningType.contains("$")) {
maybeRemoveImport(existingOwningType.substring(0, existingOwningType.indexOf('$')));
}
maybeAddImport(owningType, false);
return fieldAccess
.withTemplate(
JavaTemplate.builder(this::getCursor, template).imports(owningType).build(),
fieldAccess.getCoordinates().replace())
.withPrefix(fieldAccess.getPrefix());
}
return super.visitFieldAccess(fieldAccess, executionContext);
}

@Override
public J visitIdentifier(J.Identifier ident, ExecutionContext executionContext) {
if (isConstant(ident.getFieldType()) && !isVariableDeclaration()) {
maybeRemoveImport(existingOwningType);
maybeAddImport(owningType, false);
return ident
.withTemplate(
JavaTemplate.builder(this::getCursor, template).imports(owningType).build(),
ident.getCoordinates().replace())
.withPrefix(ident.getPrefix());
}
return super.visitIdentifier(ident, executionContext);
}

private boolean isConstant(@Nullable JavaType.Variable varType) {
return varType != null && TypeUtils.isOfClassType(varType.getOwner(), existingOwningType) &&
varType.getName().equals(constantName);
}

private boolean isVariableDeclaration() {
Cursor maybeVariable = getCursor().dropParentUntil(is -> is instanceof J.VariableDeclarations || is instanceof J.CompilationUnit);
if (!(maybeVariable.getValue() instanceof J.VariableDeclarations)) {
return false;
}
JavaType.Variable variableType = ((J.VariableDeclarations) maybeVariable.getValue()).getVariables().get(0).getVariableType();
if (variableType == null) {
return true;
}

JavaType.FullyQualified ownerFqn = TypeUtils.asFullyQualified(variableType.getOwner());
if (ownerFqn == null) {
return true;
}

return constantName.equals(((J.VariableDeclarations) maybeVariable.getValue()).getVariables().get(0).getSimpleName()) &&
existingOwningType.equals(ownerFqn.getFullyQualifiedName());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void testUpgradeDependency_latestReleaseVersion() {
}

private String getLatestBootReleaseVersion() {
return "3.0.4";
return "3.0.5";
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;
import org.springframework.sbm.java.migration.recipes.FindReplaceFieldAccessors;
import org.springframework.sbm.java.migration.recipes.RewriteConstructorInvocation;
import org.springframework.sbm.java.migration.recipes.RewriteMethodInvocation;
import org.springframework.sbm.java.migration.recipes.openrewrite.ReplaceConstantWithAnotherConstant;

import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -82,13 +82,12 @@ public ReplaceMediaType(Supplier<JavaParser> javaParserSupplier) {
mappings.put("WILDCARD", "ALL_VALUE");
mappings.put("WILDCARD_TYPE", "ALL");

doNext(new FindReplaceFieldAccessors(javaParserSupplier, "javax.ws.rs.core.MediaType", "org.springframework.http.MediaType", mappings));

doNext(new FindReplaceFieldAccessors(javaParserSupplier, "javax.ws.rs.core.MediaType", "org.springframework.util.MimeType", Map.of(
"CHARSET_PARAMETER", "PARAM_CHARSET",
"MEDIA_TYPE_WILDCARD", "WILDCARD_TYPE"
)));
mappings.forEach(
(key, value) -> doNext(new ReplaceConstantWithAnotherConstant("javax.ws.rs.core.MediaType." + key,"org.springframework.http.MediaType." + value))
);

doNext(new ReplaceConstantWithAnotherConstant("javax.ws.rs.core.MediaType.CHARSET_PARAMETER","org.springframework.util.MimeType.PARAM_CHARSET"));
doNext(new ReplaceConstantWithAnotherConstant("javax.ws.rs.core.MediaType.MEDIA_TYPE_WILDCARD","org.springframework.util.MimeType.WILDCARD_TYPE"));

// instance methods
// #isCompatible(MediaType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
*/
package org.springframework.sbm.jee.jaxrs.recipes;

import lombok.RequiredArgsConstructor;
import org.openrewrite.Recipe;
import org.openrewrite.java.ChangeType;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.springframework.sbm.java.migration.recipes.FindReplaceFieldAccessors;
import org.springframework.sbm.java.migration.recipes.RewriteMethodInvocation;
import org.springframework.sbm.java.migration.recipes.openrewrite.ReplaceConstantWithAnotherConstant;

import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -80,8 +79,9 @@ public SwapStatusForHttpStatus(Supplier<JavaParser> javaParserSupplier) {
fieldsMapping.put("UNSUPPORTED_MEDIA_TYPE", "UNSUPPORTED_MEDIA_TYPE");
fieldsMapping.put("USE_PROXY", "USE_PROXY");

doNext(new FindReplaceFieldAccessors(javaParserSupplier, "javax.ws.rs.core.Response$Status", "org.springframework.http.HttpStatus", fieldsMapping));

fieldsMapping.forEach(
(key, value) -> doNext(new ReplaceConstantWithAnotherConstant("javax.ws.rs.core.Response$Status." + key,"org.springframework.http.HttpStatus." + value))
);

// Instance methods
doNext(new RewriteMethodInvocation(methodInvocationMatcher("javax.ws.rs.core.Response.StatusType getStatusCode()")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public List<Movie> getMovies(@QueryParam("first") Integer first, @QueryParam("ma
import com.example.jeerest.Movie;
import com.example.jeerest.MoviesBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import javax.ws.rs.DELETE;
import javax.ws.rs.PUT;
Expand Down
Loading