diff --git a/rewrite-core/src/main/java/org/openrewrite/marker/TypeReference.java b/rewrite-core/src/main/java/org/openrewrite/marker/TypeReference.java new file mode 100644 index 00000000000..ebe88df0884 --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/marker/TypeReference.java @@ -0,0 +1,28 @@ +/* + * 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.marker; + +import lombok.Value; +import lombok.With; + +import java.util.UUID; + +@Value +@With +public class TypeReference implements Marker { + UUID id; + String language; +} diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java b/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java index f99abd38118..055a02424dd 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/XmlParser.java @@ -23,6 +23,7 @@ import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.internal.EncodingDetectingInputStream; +import org.openrewrite.marker.TypeReference; import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; @@ -33,6 +34,7 @@ import java.nio.file.Path; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; @@ -94,6 +96,9 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat is.isCharsetBomMarked() ).visitDocument(parser.document()); parsingListener.parsed(input, document); + if (isSpringXmlDocument(document)) { + document = (Xml.Document) addJavaTypeOrPackageMarkers().visitDocument(document, ctx); + } return requirePrintEqualsInput(document, input, relativeTo, ctx); } catch (Throwable t) { ctx.getOnError().accept(t); @@ -102,6 +107,15 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat }); } + private boolean isSpringXmlDocument(Xml.Document document) { + for (Xml.Attribute attrib : document.getRoot().getAttributes()) { + if (attrib.getKeyAsString().equals("xsi:schemaLocation") && attrib.getValueAsString().contains("www.springframework.org/schema/beans")) { + return true; + } + } + return false; + } + @Override public Stream parse(@Language("xml") String... sources) { return parse(new InMemoryExecutionContext(), sources); @@ -161,4 +175,34 @@ public String getDslName() { return "xml"; } } + + private XmlVisitor addJavaTypeOrPackageMarkers() { + XPathMatcher classXPath = new XPathMatcher("//@class[contains(., '.')]"); + XPathMatcher typeXPath = new XPathMatcher("//@type[contains(., '.')]"); + XPathMatcher tags = new XPathMatcher("//value[contains(text(), '.')]"); + + return new XmlVisitor() { + + @Override + public Xml visitAttribute(Xml.Attribute attribute, ExecutionContext ctx) { + Xml.Attribute attrib = (Xml.Attribute) super.visitAttribute(attribute, ctx); + if (classXPath.matches(getCursor()) || typeXPath.matches(getCursor())) { + return attrib.withMarkers(attrib.getMarkers().withMarkers(Collections.singletonList(new TypeReference(attrib.getId(), "Java")))); + + } + return attrib; + } + + @Override + public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { + Xml.Tag tg = (Xml.Tag) super.visitTag(tag, ctx); + if (tags.matches(getCursor())) { + if (tg.getValue().isPresent()) { + return tg.withMarkers(tg.getMarkers().withMarkers(Collections.singletonList(new TypeReference(tg.getId(), "Java")))); + } + } + return tg; + } + }; + } } diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java index 1c7449d6639..f2ccda6627f 100755 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.openrewrite.ExecutionContext; import org.openrewrite.Issue; +import org.openrewrite.marker.TypeReference; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import org.openrewrite.xml.tree.Xml; @@ -30,6 +31,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.openrewrite.test.RewriteTest.toRecipe; import static org.openrewrite.xml.Assertions.xml; @@ -397,6 +399,41 @@ void preserveWhitespaceOnEntities() { ); } + @Test + void springXmlMarkers() { + rewriteRun( + xml( + """ + + + + + + + + + java.lang.String + + + + + + """, + spec -> spec.afterRecipe(after -> { + Xml.Tag testBean = ((Xml.Tag) after.getRoot().getContent().get(0)); + assertTrue(testBean.getAttributes().get(1).getMarkers().getMarkers().stream().anyMatch(TypeReference.class::isInstance)); + Xml.Tag unnamedBeanInSiblingProperty = ((Xml.Tag) ((Xml.Tag) testBean.getContent().get(1)).getContent().get(0)); + assertTrue(unnamedBeanInSiblingProperty.getAttributes().get(0).getMarkers().getMarkers().stream().anyMatch(TypeReference.class::isInstance)); + Xml.Tag ageProperty = ((Xml.Tag) unnamedBeanInSiblingProperty.getContent().get(0)); + assertTrue(ageProperty.getAttributes().get(2).getMarkers().getMarkers().stream().anyMatch(TypeReference.class::isInstance)); + Xml.Tag someNameValue = (Xml.Tag) ((Xml.Tag) unnamedBeanInSiblingProperty.getContent().get(1)).getContent().get(0); + assertTrue(someNameValue.getMarkers().getMarkers().stream().anyMatch(TypeReference.class::isInstance)); + }) + ) + ); + } + @DisabledOnOs(OS.WINDOWS) @ParameterizedTest @ValueSource(strings = {