diff --git a/.travis.yml b/.travis.yml index 99a559dad..9c70b38bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,10 @@ jdk: cache: directories: - $HOME/.m2 +branches: + only: + - master + - /^release-.+$/ script: > mvn test \ -Dteavm.test.skip=false \ diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 1892901eb..a4c57f160 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -766,7 +766,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * obtains all implementation classes that are enumerated there.

*/ public void installPlugins() { - for (TeaVMPlugin plugin : ServiceLoader.load(TeaVMPlugin.class, classLoader)) { + for (TeaVMPlugin plugin : TeaVMPluginLoader.load(classLoader)) { plugin.install(this); } } diff --git a/core/src/main/java/org/teavm/vm/TeaVMPluginLoader.java b/core/src/main/java/org/teavm/vm/TeaVMPluginLoader.java index 1994c26cf..b4db270ed 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMPluginLoader.java +++ b/core/src/main/java/org/teavm/vm/TeaVMPluginLoader.java @@ -73,7 +73,7 @@ public final class TeaVMPluginLoader { .collect(Collectors.toList()); } - public static List orderPlugins(ClassLoader classLoader, Set classNames) { + static List orderPlugins(ClassLoader classLoader, Set classNames) { Map descriptors = new HashMap<>(); try { for (String className : classNames) { @@ -160,11 +160,11 @@ public final class TeaVMPluginLoader { throw new IllegalStateException("Plugin " + descriptor.name + " has both before and after annotations"); } - descriptor.beforeList.addAll(Arrays.asList(descriptor.before)); - for (String after : descriptor.after) { - PluginDescriptor afterDescriptor = descriptors.get(after); - if (afterDescriptor != null && afterDescriptor.reachable) { - afterDescriptor.beforeList.add(descriptor.name); + descriptor.afterList.addAll(Arrays.asList(descriptor.after)); + for (String before : descriptor.before) { + PluginDescriptor beforeDescriptor = descriptors.get(before); + if (beforeDescriptor != null && beforeDescriptor.reachable) { + beforeDescriptor.afterList.add(descriptor.name); } } } @@ -180,14 +180,15 @@ public final class TeaVMPluginLoader { } path.add(descriptor.name); - for (String before : descriptor.beforeList) { - PluginDescriptor beforeDescriptor = descriptors.get(before); - if (beforeDescriptor != null) { - if (visited.contains(before) && !emmited.contains(before)) { + for (String after : descriptor.afterList) { + PluginDescriptor afterDescriptor = descriptors.get(after); + if (afterDescriptor != null && afterDescriptor.reachable) { + if (visited.contains(after) && !emmited.contains(after)) { List loop = new ArrayList<>(); + Collections.reverse(path); for (String pathElem : path) { loop.add(pathElem); - if (pathElem.equals(descriptor.name)) { + if (pathElem.equals(afterDescriptor.name)) { break; } } @@ -195,7 +196,7 @@ public final class TeaVMPluginLoader { throw new IllegalStateException("Circular dependency found: " + loop.stream() .collect(Collectors.joining(" -> "))); } - orderDescriptors(beforeDescriptor, descriptors, list, visited, emmited, path); + orderDescriptors(afterDescriptor, descriptors, list, visited, emmited, path); } } @@ -260,7 +261,7 @@ public final class TeaVMPluginLoader { String[] requires = new String[0]; String[] before = new String[0]; String[] after = new String[0]; - List beforeList = new ArrayList<>(); + List afterList = new ArrayList<>(); boolean reachable; } } diff --git a/core/src/test/java/org/teavm/vm/PluginLoaderTest.java b/core/src/test/java/org/teavm/vm/PluginLoaderTest.java index aea0b4fc6..99301ba02 100644 --- a/core/src/test/java/org/teavm/vm/PluginLoaderTest.java +++ b/core/src/test/java/org/teavm/vm/PluginLoaderTest.java @@ -15,12 +15,13 @@ */ package org.teavm.vm; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import org.junit.Test; +import org.teavm.vm.spi.After; import org.teavm.vm.spi.Before; import org.teavm.vm.spi.Requires; import org.teavm.vm.spi.TeaVMHost; @@ -37,6 +38,25 @@ public class PluginLoaderTest { assertThat(plugins.size(), is(2)); assertThat(plugins.get(0), is(B.class.getName())); assertThat(plugins.get(1), is(A.class.getName())); + + plugins = order(C.class, D.class); + assertThat(plugins.size(), is(2)); + assertThat(plugins.get(0), is(C.class.getName())); + assertThat(plugins.get(1), is(D.class.getName())); + } + + @Test + public void respectsPluginDependency() { + List plugins = order(B.class); + assertThat(plugins.size(), is(0)); + + plugins = order(A.class); + assertThat(plugins.size(), is(1)); + } + + @Test(expected = IllegalStateException.class) + public void detectsCircularDependency() { + order(Pre.class, Head.class, Tail.class); } private List order(Class... classes) { @@ -57,4 +77,39 @@ public class PluginLoaderTest { public void install(TeaVMHost host) { } } + + static class C implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + } + } + + @After(C.class) + @Requires(C.class) + static class D implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + } + } + + @Before(Head.class) + static class Pre implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + } + } + + @Before(Tail.class) + static class Head implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + } + } + + @Before(Head.class) + static class Tail implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + } + } } diff --git a/pom.xml b/pom.xml index 21282c232..bf1e6e088 100644 --- a/pom.xml +++ b/pom.xml @@ -243,7 +243,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 2.15 + 2.16 validate