Skip to content

Commit

Permalink
Support scanning of configurable refactor rules
Browse files Browse the repository at this point in the history
  • Loading branch information
jkschneider committed Jun 3, 2020
1 parent 5516fd8 commit 7986913
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 0 deletions.
57 changes: 57 additions & 0 deletions rewrite-core/src/main/java/org/openrewrite/Refactor.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@
*/
package org.openrewrite;

import io.github.classgraph.*;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import lombok.Getter;
import org.eclipse.microprofile.config.Config;
import org.openrewrite.config.AutoConfigure;
import org.openrewrite.internal.lang.NonNullApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;
import java.util.*;
import java.util.function.Function;

Expand All @@ -35,6 +41,8 @@
*/
@NonNullApi
public class Refactor<S extends SourceFile, T extends Tree> {
private final Logger logger = LoggerFactory.getLogger(Refactor.class);

@Getter
private final S original;

Expand All @@ -58,6 +66,55 @@ public final Refactor<S, T> visit(Iterable<SourceVisitor<T>> visitors) {
return this;
}

public final Refactor<S, T> scan(Config config, String... whitelistPackages) {
try (ScanResult scanResult = new ClassGraph()
.whitelistPackages(whitelistPackages)
.enableMethodInfo()
.enableAnnotationInfo()
.ignoreClassVisibility()
.ignoreMethodVisibility()
.scan()) {
for (ClassInfo classInfo : scanResult.getClassesWithMethodAnnotation(AutoConfigure.class.getName())) {
for (MethodInfo methodInfo : classInfo.getMethodInfo()) {
AnnotationInfo annotationInfo = methodInfo.getAnnotationInfo(AutoConfigure.class.getName());
if (annotationInfo != null) {
MethodParameterInfo[] parameterInfo = methodInfo.getParameterInfo();
if (parameterInfo.length != 1 || !parameterInfo[0].getTypeDescriptor()
.toString().equals("org.eclipse.microprofile.config.Config")) {
logger.debug("Unable to configure refactoring visitor {}#{} because it did not have a single " +
"parameter of type org.eclipse.microprofile.config.Config",
classInfo.getSimpleName(), methodInfo.getName());
continue;
}

Method method = methodInfo.loadClassAndGetMethod();

Type genericSuperclass = method.getReturnType().getGenericSuperclass();
if(genericSuperclass instanceof ParameterizedType) {
Type[] sourceFileType = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
if (sourceFileType[0].equals(original.getClass())) {
if ((methodInfo.getModifiers() & Modifier.PUBLIC) == 0 ||
(classInfo.getModifiers() & Modifier.PUBLIC) == 0) {
method.setAccessible(true);
}

try {
//noinspection unchecked
visit((SourceVisitor<T>) method.invoke(null, config));
} catch (IllegalAccessException | InvocationTargetException e) {
logger.warn("Failed to configure refactoring visitor {}#{}",
classInfo.getSimpleName(), methodInfo.getName(), e);
}
}
}
}
}
}
}

return this;
}

/**
* Shortcut for building refactoring operations for a collection of like-typed {@link Tree} elements.
*
Expand Down
123 changes: 123 additions & 0 deletions rewrite-core/src/test/kotlin/org/openrewrite/RefactorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2020 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;

import org.eclipse.microprofile.config.Config;
import org.junit.jupiter.api.Test;
import org.openrewrite.config.AutoConfigure;

import java.util.Map;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.openrewrite.Formatting.EMPTY;
import static org.openrewrite.Tree.randomId;
import static org.openrewrite.config.MapConfigSource.mapConfig;

public class RefactorTest {
@Test
void scanAutoConfigurableRules() {
PlainText fixed = new PlainText(randomId(), "Hello World!", EMPTY)
.refactor()
.scan(mapConfig("test.ChangeText.toText", "Hello Jon!"), "org.openrewrite")
.fix().getFixed();

assertThat(fixed.print()).isEqualTo("Hello Jon!");
}
}

class ChangeText extends SourceVisitor<PlainText> implements RefactorVisitorSupport {
private final String toText;

public ChangeText(String toText) {
super("test.ChangeText");
this.toText = toText;
}

@AutoConfigure
private static ChangeText configure(Config config) {
return new ChangeText(config.getValue("test.ChangeText.toText", String.class));
}

@Override
public PlainText visitTree(Tree tree) {
PlainText text = (PlainText) tree;
return text.withText(toText);
}

@Override
public PlainText defaultTo(Tree t) {
return (PlainText) t;
}
}

class PlainText implements SourceFile, Tree {
private final UUID id;
private final String text;
private final Formatting formatting;

public PlainText(UUID id, String text, Formatting formatting) {
this.id = id;
this.text = text;
this.formatting = formatting;
}

public Refactor<PlainText, PlainText> refactor() {
return new Refactor<>(this);
}

@Override
public String getSourcePath() {
return null;
}

@Override
public Map<Metadata, String> getMetadata() {
return null;
}

@Override
public String getFileType() {
return "txt";
}

@Override
public Formatting getFormatting() {
return formatting;
}

@Override
public UUID getId() {
return id;
}

public PlainText withText(String toText) {
return new PlainText(id, toText, formatting);
}

@SuppressWarnings("unchecked")
@Override
public <T extends Tree> T withFormatting(Formatting fmt) {
return (T) new PlainText(id, text, fmt);
}

@Override
public String print() {
return formatting.getPrefix() + text + formatting.getSuffix();
}
}


0 comments on commit 7986913

Please sign in to comment.