Skip to content

Commit c85b731

Browse files
committed
Refactor plugin to avoid implementing general logic and adjust to better match the other plugin implementations.
1 parent 29f4f6c commit c85b731

4 files changed

Lines changed: 302 additions & 147 deletions

File tree

byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2736,6 +2736,174 @@ public void close() {
27362736
}
27372737
}
27382738

2739+
/**
2740+
* A compound source that combines multiple sources into a single representation.
2741+
*/
2742+
@HashCodeAndEqualsPlugin.Enhance
2743+
class Compound implements Source {
2744+
2745+
/**
2746+
* The represented sources.
2747+
*/
2748+
private final Collection<? extends Source> sources;
2749+
2750+
/**
2751+
* Creates a new compound source.
2752+
*
2753+
* @param sources The represented sources.
2754+
*/
2755+
public Compound(Collection<? extends Source> sources) {
2756+
this.sources = sources;
2757+
}
2758+
2759+
/**
2760+
* {@inheritDoc}
2761+
*/
2762+
public Source.Origin read() throws IOException {
2763+
if (sources.isEmpty()) {
2764+
return Empty.INSTANCE;
2765+
}
2766+
List<Source.Origin> origins = new ArrayList<Source.Origin>(sources.size());
2767+
try {
2768+
for (Source source : sources) {
2769+
origins.add(source.read());
2770+
}
2771+
} catch (IOException exception) {
2772+
for (Source.Origin origin : origins) {
2773+
origin.close();
2774+
}
2775+
throw exception;
2776+
}
2777+
return new Origin(origins);
2778+
}
2779+
2780+
/**
2781+
* Implements a compound {@link Source.Origin}.
2782+
*/
2783+
@HashCodeAndEqualsPlugin.Enhance
2784+
protected static class Origin implements Source.Origin {
2785+
2786+
/**
2787+
* A list of represented origins.
2788+
*/
2789+
private final List<Source.Origin> origins;
2790+
2791+
/**
2792+
* Creates a new compound origin.
2793+
*
2794+
* @param origins A list of represented origins.
2795+
*/
2796+
protected Origin(List<Source.Origin> origins) {
2797+
this.origins = origins;
2798+
}
2799+
2800+
/**
2801+
* {@inheritDoc}
2802+
*/
2803+
public Manifest getManifest() throws IOException {
2804+
for (Source.Origin origin : origins) {
2805+
Manifest manifest = origin.getManifest();
2806+
if (manifest != null) {
2807+
return manifest;
2808+
}
2809+
}
2810+
return NO_MANIFEST;
2811+
}
2812+
2813+
/**
2814+
* {@inheritDoc}
2815+
*/
2816+
public ClassFileLocator getClassFileLocator() {
2817+
List<ClassFileLocator> classFileLocators = new ArrayList<ClassFileLocator>(origins.size());
2818+
for (Source.Origin origin : origins) {
2819+
classFileLocators.add(origin.getClassFileLocator());
2820+
}
2821+
return new ClassFileLocator.Compound(classFileLocators);
2822+
}
2823+
2824+
/**
2825+
* {@inheritDoc}
2826+
*/
2827+
public Iterator<Element> iterator() {
2828+
return new CompoundIterator(origins);
2829+
}
2830+
2831+
/**
2832+
* {@inheritDoc}
2833+
*/
2834+
public void close() throws IOException {
2835+
for (Source.Origin origin : origins) {
2836+
origin.close();
2837+
}
2838+
}
2839+
2840+
/**
2841+
* A compound iterator that combines several iterables.
2842+
*/
2843+
protected static class CompoundIterator implements Iterator<Element> {
2844+
2845+
/**
2846+
* The current iterator or {@code null} if no such iterator is defined.
2847+
*/
2848+
@MaybeNull
2849+
private Iterator<? extends Element> current;
2850+
2851+
/**
2852+
* A backlog of iterables to still consider.
2853+
*/
2854+
private final List<? extends Iterable<? extends Element>> backlog;
2855+
2856+
/**
2857+
* Creates a compound iterator.
2858+
*
2859+
* @param iterables The iterables to consider.
2860+
*/
2861+
protected CompoundIterator(List<? extends Iterable<? extends Element>> iterables) {
2862+
backlog = iterables;
2863+
forward();
2864+
}
2865+
2866+
/**
2867+
* {@inheritDoc}
2868+
*/
2869+
public boolean hasNext() {
2870+
return current != null && current.hasNext();
2871+
}
2872+
2873+
/**
2874+
* {@inheritDoc}
2875+
*/
2876+
public Element next() {
2877+
try {
2878+
if (current != null) {
2879+
return current.next();
2880+
} else {
2881+
throw new NoSuchElementException();
2882+
}
2883+
} finally {
2884+
forward();
2885+
}
2886+
}
2887+
2888+
/**
2889+
* Forwards the iterator to the next relevant iterable.
2890+
*/
2891+
private void forward() {
2892+
while ((current == null || !current.hasNext()) && !backlog.isEmpty()) {
2893+
current = backlog.remove(0).iterator();
2894+
}
2895+
}
2896+
2897+
/**
2898+
* {@inheritDoc}
2899+
*/
2900+
public void remove() {
2901+
throw new UnsupportedOperationException("remove");
2902+
}
2903+
}
2904+
}
2905+
}
2906+
27392907
/**
27402908
* A source that represents a collection of in-memory resources that are represented as byte arrays.
27412909
*/
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package net.bytebuddy.build;
2+
3+
import net.bytebuddy.dynamic.ClassFileLocator;
4+
import org.junit.Before;
5+
import org.junit.Rule;
6+
import org.junit.Test;
7+
import org.junit.rules.MethodRule;
8+
import org.mockito.Mock;
9+
import org.mockito.Mockito;
10+
import org.mockito.invocation.InvocationOnMock;
11+
import org.mockito.junit.MockitoJUnit;
12+
import org.mockito.stubbing.Answer;
13+
14+
import java.util.Arrays;
15+
import java.util.Collections;
16+
import java.util.Iterator;
17+
import java.util.jar.Manifest;
18+
19+
import static org.hamcrest.CoreMatchers.*;
20+
import static org.hamcrest.MatcherAssert.assertThat;
21+
import static org.mockito.Mockito.verify;
22+
import static org.mockito.Mockito.when;
23+
24+
public class PluginEngineSourceCompoundTest {
25+
26+
private static final String FOO = "foo";
27+
28+
@Rule
29+
public MethodRule mockitoRule = MockitoJUnit.rule().silent();
30+
31+
@Mock
32+
private Plugin.Engine.Source left;
33+
34+
@Mock
35+
private Plugin.Engine.Source right;
36+
37+
@Mock
38+
private Plugin.Engine.Source.Origin leftOrigin;
39+
40+
@Mock
41+
private Plugin.Engine.Source.Origin rightOrigin;
42+
43+
@Mock
44+
private ClassFileLocator leftLocator;
45+
46+
@Mock
47+
private ClassFileLocator rightLocator;
48+
49+
@Mock
50+
private Plugin.Engine.Source.Element leftElement;
51+
52+
@Mock
53+
private Plugin.Engine.Source.Element rightElement;
54+
55+
@Before
56+
public void setUp() throws Exception {
57+
when(left.read()).thenReturn(leftOrigin);
58+
when(right.read()).thenReturn(rightOrigin);
59+
when(leftOrigin.getClassFileLocator()).thenReturn(leftLocator);
60+
when(rightOrigin.getClassFileLocator()).thenReturn(rightLocator);
61+
when(leftLocator.locate(Mockito.any(String.class))).thenReturn(new ClassFileLocator.Resolution.Illegal(FOO));
62+
when(rightLocator.locate(Mockito.any(String.class))).thenReturn(new ClassFileLocator.Resolution.Illegal(FOO));
63+
when(leftOrigin.iterator()).then(new Answer<Iterator<Plugin.Engine.Source.Element>>() {
64+
@Override
65+
public Iterator<Plugin.Engine.Source.Element> answer(InvocationOnMock invocation) {
66+
return Collections.singleton(leftElement).iterator();
67+
}
68+
});
69+
when(rightOrigin.iterator()).then(new Answer<Iterator<Plugin.Engine.Source.Element>>() {
70+
@Override
71+
public Iterator<Plugin.Engine.Source.Element> answer(InvocationOnMock invocation) {
72+
return Collections.singleton(rightElement).iterator();
73+
}
74+
});
75+
}
76+
77+
@Test
78+
public void testEmptyCompound() throws Exception {
79+
assertThat(new Plugin.Engine.Source.Compound(Collections.emptyList()).read(), sameInstance((Plugin.Engine.Source.Origin) Plugin.Engine.Source.Empty.INSTANCE));
80+
}
81+
82+
@Test
83+
public void testClassFileLocator() throws Exception {
84+
assertThat(new Plugin.Engine.Source.Compound(Arrays.asList(left, right)).read().getClassFileLocator().locate(FOO).isResolved(), is(false));
85+
verify(leftLocator).locate(FOO);
86+
verify(rightLocator).locate(FOO);
87+
}
88+
89+
@Test
90+
public void testManifest() throws Exception {
91+
assertThat(new Plugin.Engine.Source.Compound(Arrays.asList(left, right)).read().getManifest(), nullValue(Manifest.class));
92+
verify(leftOrigin).getManifest();
93+
verify(rightOrigin).getManifest();
94+
}
95+
96+
@Test
97+
public void testIteration() throws Exception {
98+
Iterator<Plugin.Engine.Source.Element> iterator = new Plugin.Engine.Source.Compound(Arrays.asList(left, right)).read().iterator();
99+
assertThat(iterator.hasNext(), is(true));
100+
assertThat(iterator.next(), is(leftElement));
101+
assertThat(iterator.hasNext(), is(true));
102+
assertThat(iterator.next(), is(rightElement));
103+
assertThat(iterator.hasNext(), is(false));
104+
105+
}
106+
107+
@Test
108+
public void testClose() throws Exception {
109+
new Plugin.Engine.Source.Compound(Arrays.asList(left, right)).read().close();
110+
verify(leftOrigin).close();
111+
verify(rightOrigin).close();
112+
}
113+
}

byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyLocalClassesEnhancerTask.java

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222
import net.bytebuddy.build.BuildLogger;
2323
import net.bytebuddy.build.EntryPoint;
2424
import net.bytebuddy.build.Plugin;
25-
import net.bytebuddy.description.type.TypeDescription;
2625
import net.bytebuddy.dynamic.ClassFileLocator;
27-
import net.bytebuddy.dynamic.DynamicType;
28-
import net.bytebuddy.dynamic.scaffold.TypeValidation;
2926
import net.bytebuddy.dynamic.scaffold.inline.MethodNameTransformer;
3027
import org.gradle.api.Action;
3128
import org.gradle.api.DefaultTask;
@@ -140,12 +137,10 @@ public void execute() {
140137
classFileLocators.add(ClassFileLocator.ForClassLoader.of(ByteBuddy.class.getClassLoader()));
141138
ClassFileLocator classFileLocator = new ClassFileLocator.Compound(classFileLocators);
142139
try {
143-
List<Directory> directories = getLocalClassesDirs().get();
144-
Set<Plugin.Engine.Source.Origin> origins = new HashSet<>();
145-
for (Directory directory : directories) {
146-
origins.add(new Plugin.Engine.Source.ForFolder(directory.getAsFile()));
140+
Set<Plugin.Engine.Source> sources = new LinkedHashSet<Plugin.Engine.Source>();
141+
for (Directory directory : getLocalClassesDirs().get()) {
142+
sources.add(new Plugin.Engine.Source.ForFolder(directory.getAsFile()));
147143
}
148-
MethodNameTransformer methodNameTransformer = MethodNameTransformer.Suffixing.withRandomSuffix();
149144
ClassLoader classLoader = new URLClassLoader(
150145
toUrls(getByteBuddyClasspath().getFiles()),
151146
new URLClassLoader(toUrls(getAndroidBootClasspath().getFiles()), ByteBuddy.class.getClassLoader()));
@@ -175,15 +170,17 @@ public void execute() {
175170
throw new IllegalStateException("Cannot resolve plugin: " + name, throwable);
176171
}
177172
}
178-
Plugin.Engine.Summary summary = Plugin.Engine.Default.of(new EntryPoint.Unvalidated(EntryPoint.Default.DECORATE), classFileVersion, methodNameTransformer)
173+
Plugin.Engine.Summary summary = Plugin.Engine.Default.of(new EntryPoint.Unvalidated(EntryPoint.Default.DECORATE),
174+
classFileVersion,
175+
MethodNameTransformer.Suffixing.withRandomSuffix())
179176
.with(classFileLocator)
180-
.apply(new CompoundSourceOrigin(origins), new Plugin.Engine.Target.ForFolder(getOutputDir().get().getAsFile()), factories);
177+
.apply(new Plugin.Engine.Source.Compound(sources), new Plugin.Engine.Target.ForFolder(getOutputDir().get().getAsFile()), factories);
181178
if (!summary.getFailed().isEmpty()) {
182-
throw new IllegalStateException(summary.getFailed() + " type transformations have failed");
179+
throw new IllegalStateException(summary.getFailed() + " local type transformations have failed");
183180
} else if (summary.getTransformed().isEmpty()) {
184-
getLogger().info("No types were transformed during plugin execution");
181+
getLogger().info("No local types were transformed during plugin execution");
185182
} else {
186-
getLogger().info("Transformed {} type(s)", summary.getTransformed().size());
183+
getLogger().info("Transformed {} local type(s)", summary.getTransformed().size());
187184
}
188185
} finally {
189186
if (classLoader instanceof Closeable) {
@@ -205,33 +202,36 @@ public void execute() {
205202
* A configuration action for the {@link ByteBuddyLocalClassesEnhancerTask} task.
206203
*/
207204
protected static class ConfigurationAction implements Action<ByteBuddyLocalClassesEnhancerTask> {
205+
208206
/**
209-
* The current variant Byte Buddy configuration.
207+
* The current variant's Byte Buddy configuration.
210208
*/
211-
private final Configuration bytebuddyClasspath;
209+
private final Configuration byteBuddyConfiguration;
212210
/**
213211
* The android gradle extension.
214212
*/
213+
215214
private final BaseExtension androidExtension;
216215
/**
217216
* The current variant's runtime classpath.
218217
*/
218+
219219
private final FileCollection runtimeClasspath;
220220

221221
/**
222-
* @param bytebuddyClasspath The current variant Byte Buddy configuration.
223-
* @param androidExtension The android gradle extension.
224-
* @param runtimeClasspath The current variant's runtime classpath.
222+
* @param byteBuddyConfiguration The current variant Byte Buddy configuration.
223+
* @param androidExtension The android gradle extension.
224+
* @param runtimeClasspath The current variant's runtime classpath.
225225
*/
226-
public ConfigurationAction(Configuration bytebuddyClasspath, BaseExtension androidExtension, FileCollection runtimeClasspath) {
227-
this.bytebuddyClasspath = bytebuddyClasspath;
226+
public ConfigurationAction(Configuration byteBuddyConfiguration, BaseExtension androidExtension, FileCollection runtimeClasspath) {
227+
this.byteBuddyConfiguration = byteBuddyConfiguration;
228228
this.androidExtension = androidExtension;
229229
this.runtimeClasspath = runtimeClasspath;
230230
}
231231

232232
@Override
233233
public void execute(ByteBuddyLocalClassesEnhancerTask task) {
234-
task.getByteBuddyClasspath().from(bytebuddyClasspath);
234+
task.getByteBuddyClasspath().from(byteBuddyConfiguration);
235235
task.getAndroidBootClasspath().from(androidExtension.getBootClasspath());
236236
task.getRuntimeClasspath().from(runtimeClasspath);
237237
task.getJavaTargetCompatibilityVersion().set(androidExtension.getCompileOptions().getTargetCompatibility());

0 commit comments

Comments
 (0)