Skip to content

Commit 36f7ef8

Browse files
committed
Revert joobyRun classpath to flatten otherwise MVC route wont load
1 parent fd7675f commit 36f7ef8

File tree

6 files changed

+129
-158
lines changed

6 files changed

+129
-158
lines changed

jooby/src/main/java/io/jooby/internal/mvc/MvcCompiler.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.jooby.Multipart;
2121
import io.jooby.QueryString;
2222
import io.jooby.Route;
23+
import io.jooby.Throwing;
2324
import io.jooby.Value;
2425
import io.jooby.internal.ValueInjector;
2526
import io.jooby.internal.reflect.$Types;
@@ -30,15 +31,22 @@
3031
import org.objectweb.asm.Type;
3132

3233
import javax.inject.Provider;
34+
import java.io.IOException;
3335
import java.lang.reflect.Method;
3436
import java.lang.reflect.Parameter;
3537
import java.lang.reflect.ParameterizedType;
38+
import java.net.URLClassLoader;
39+
import java.nio.file.Files;
40+
import java.nio.file.Path;
41+
import java.nio.file.Paths;
3642
import java.util.LinkedHashSet;
3743
import java.util.Set;
3844
import java.util.function.BiConsumer;
3945
import java.util.function.Consumer;
46+
import java.util.stream.Stream;
4047

4148
import static java.util.Arrays.asList;
49+
import static java.util.Arrays.sort;
4250
import static org.objectweb.asm.Opcodes.AASTORE;
4351
import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
4452
import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
@@ -137,11 +145,16 @@ public class MvcCompiler {
137145
public static Class<? extends MvcHandler> compileClass(MvcMethod method)
138146
throws ClassNotFoundException {
139147
byte[] bytes = compile(method);
140-
return (Class<? extends MvcHandler>) new ClassLoader() {
141-
@Override protected Class<?> findClass(String name) {
142-
return defineClass(name, bytes, 0, bytes.length);
148+
String handlername = method.getHandlerName();
149+
ClassLoader parent = method.getClass().getClassLoader();
150+
return (Class<? extends MvcHandler>) new ClassLoader(parent) {
151+
@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
152+
if (handlername.equals(name)) {
153+
return defineClass(name, bytes, 0, bytes.length);
154+
}
155+
return super.findClass(name);
143156
}
144-
}.loadClass(method.getHandlerName());
157+
}.loadClass(handlername);
145158
}
146159

147160
public static byte[] compile(MvcMethod metadata) {

modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/JoobyRun.java

Lines changed: 79 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.gradle.tooling.ResultHandler;
3232

3333
import java.io.File;
34+
import java.lang.reflect.InvocationTargetException;
3435
import java.nio.file.Files;
3536
import java.nio.file.Path;
3637
import java.util.Arrays;
@@ -58,82 +59,87 @@ public class JoobyRun extends DefaultTask {
5859
private ProjectConnection connection;
5960

6061
@TaskAction
61-
public void run() throws Exception {
62-
Project current = getProject();
63-
List<Project> projects = Arrays.asList(current);
64-
65-
String mainClass = projects.stream()
66-
.filter(it -> it.getProperties().containsKey("mainClassName"))
67-
.map(it -> it.getProperties().get("mainClassName").toString())
68-
.findFirst()
69-
.orElseThrow(() -> new IllegalArgumentException(
70-
"Application class not found. Did you forget to set `mainClassName`?"));
71-
72-
HotSwap hotSwap = new HotSwap(current.getName(), mainClass, executionMode);
73-
74-
connection = GradleConnector.newConnector()
75-
.useInstallation(current.getGradle().getGradleHomeDir())
76-
.forProjectDirectory(current.getRootDir())
77-
.connect();
78-
79-
BuildLauncher compiler = connection.newBuild()
80-
.setStandardError(System.err)
81-
.setStandardOutput(System.out)
82-
.forTasks("classes");
83-
84-
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
85-
hotSwap.shutdown();
86-
connection.close();
87-
}));
88-
89-
BiConsumer<String, Path> onFileChanged = (event, path) -> {
90-
if (isCompileExtension(path)) {
91-
compiler.run(new ResultHandler<Void>() {
92-
@Override public void onComplete(Void result) {
93-
getLogger().debug("Restarting application on file change: " + path);
94-
hotSwap.restart();
95-
}
96-
97-
@Override public void onFailure(GradleConnectionException failure) {
98-
getLogger().debug("Compilation error found: " + path);
99-
}
100-
});
101-
} else if (isRestartExtension(path)) {
102-
getLogger().debug("Restarting application on file change: " + path);
103-
hotSwap.restart();
104-
} else {
105-
getLogger().debug("Ignoring file change: " + path);
106-
}
107-
};
108-
109-
for (Project project : projects) {
110-
getLogger().debug("Adding project: " + project.getName());
111-
112-
SourceSet sourceSet = sourceSet(project);
113-
// main/resources
114-
sourceSet.getResources().getSrcDirs().stream()
115-
.map(File::toPath)
116-
.forEach(file -> hotSwap.addResource(file, onFileChanged));
117-
// conf directory
118-
Path conf = project.getProjectDir().toPath().resolve("conf");
119-
hotSwap.addResource(conf, onFileChanged);
120-
121-
// build classes
122-
binDirectories(project, sourceSet).forEach(hotSwap::addResource);
123-
124-
Set<Path> src = sourceDirectories(project, sourceSet);
125-
if (src.isEmpty()) {
126-
getLogger().debug("Compiler is off in favor of Eclipse compiler.");
127-
binDirectories(project, sourceSet).forEach(path -> hotSwap.addResource(path, onFileChanged));
128-
} else {
129-
src.forEach(path -> hotSwap.addResource(path, onFileChanged));
62+
public void run() throws Throwable {
63+
try {
64+
Project current = getProject();
65+
List<Project> projects = Arrays.asList(current);
66+
67+
String mainClass = projects.stream()
68+
.filter(it -> it.getProperties().containsKey("mainClassName"))
69+
.map(it -> it.getProperties().get("mainClassName").toString())
70+
.findFirst()
71+
.orElseThrow(() -> new IllegalArgumentException(
72+
"Application class not found. Did you forget to set `mainClassName`?"));
73+
74+
HotSwap hotSwap = new HotSwap(current.getName(), mainClass, executionMode);
75+
76+
connection = GradleConnector.newConnector()
77+
.useInstallation(current.getGradle().getGradleHomeDir())
78+
.forProjectDirectory(current.getRootDir())
79+
.connect();
80+
81+
BuildLauncher compiler = connection.newBuild()
82+
.setStandardError(System.err)
83+
.setStandardOutput(System.out)
84+
.forTasks("classes");
85+
86+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
87+
hotSwap.shutdown();
88+
connection.close();
89+
}));
90+
91+
BiConsumer<String, Path> onFileChanged = (event, path) -> {
92+
if (isCompileExtension(path)) {
93+
compiler.run(new ResultHandler<Void>() {
94+
@Override public void onComplete(Void result) {
95+
getLogger().debug("Restarting application on file change: " + path);
96+
hotSwap.restart();
97+
}
98+
99+
@Override public void onFailure(GradleConnectionException failure) {
100+
getLogger().debug("Compilation error found: " + path);
101+
}
102+
});
103+
} else if (isRestartExtension(path)) {
104+
getLogger().debug("Restarting application on file change: " + path);
105+
hotSwap.restart();
106+
} else {
107+
getLogger().debug("Ignoring file change: " + path);
108+
}
109+
};
110+
111+
for (Project project : projects) {
112+
getLogger().debug("Adding project: " + project.getName());
113+
114+
SourceSet sourceSet = sourceSet(project);
115+
// main/resources
116+
sourceSet.getResources().getSrcDirs().stream()
117+
.map(File::toPath)
118+
.forEach(file -> hotSwap.addResource(file, onFileChanged));
119+
// conf directory
120+
Path conf = project.getProjectDir().toPath().resolve("conf");
121+
hotSwap.addResource(conf, onFileChanged);
122+
123+
// build classes
124+
binDirectories(project, sourceSet).forEach(hotSwap::addResource);
125+
126+
Set<Path> src = sourceDirectories(project, sourceSet);
127+
if (src.isEmpty()) {
128+
getLogger().debug("Compiler is off in favor of Eclipse compiler.");
129+
binDirectories(project, sourceSet)
130+
.forEach(path -> hotSwap.addResource(path, onFileChanged));
131+
} else {
132+
src.forEach(path -> hotSwap.addResource(path, onFileChanged));
133+
}
134+
135+
dependencies(project, sourceSet).forEach(hotSwap::addResource);
130136
}
131137

132-
dependencies(project, sourceSet).forEach(hotSwap::addResource);
138+
// Block current thread.
139+
hotSwap.start();
140+
} catch (InvocationTargetException x) {
141+
throw x.getCause();
133142
}
134-
135-
// Block current thread.
136-
hotSwap.start();
137143
}
138144

139145
private Set<Path> binDirectories(Project project, SourceSet sourceSet) {

modules/jooby-maven-plugin/src/main/java/io/jooby/maven/JoobyRun.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.eclipse.aether.graph.Dependency;
4343

4444
import java.io.File;
45+
import java.lang.reflect.InvocationTargetException;
4546
import java.nio.file.Files;
4647
import java.nio.file.Path;
4748
import java.nio.file.Paths;
@@ -91,7 +92,8 @@ public class JoobyRun extends AbstractMojo {
9192
.filter(it -> it.getProperties().containsKey(APP_CLASS))
9293
.findFirst()
9394
.map(it -> it.getProperties().getProperty(APP_CLASS))
94-
.orElseThrow(() -> new MojoExecutionException("Application class not found"));
95+
.orElseThrow(() -> new MojoExecutionException(
96+
"Application class not found. Did you forget to set `application.class`?"));
9597
}
9698
if (executionMode == null) {
9799
executionMode = "DEFAULT";
@@ -153,7 +155,13 @@ public class JoobyRun extends AbstractMojo {
153155
} catch (MojoExecutionException | MojoFailureException x) {
154156
throw x;
155157
} catch (Exception x) {
156-
throw new MojoFailureException("jooby-run resulted in exception", x);
158+
Throwable cause;
159+
if (x instanceof InvocationTargetException) {
160+
cause = x.getCause();
161+
} else {
162+
cause = x;
163+
}
164+
throw new MojoFailureException("jooby-run resulted in exception", cause);
157165
}
158166
}
159167

modules/jooby-run/src/main/java/io/jooby/run/HotSwap.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,7 @@ public void start() {
116116
App app = new App(createApp.invoke(null, new String[0], executionModeValue, appClass));
117117
server = app.start();
118118
} catch (Exception x) {
119-
Throwable cause;
120-
if (x instanceof InvocationTargetException) {
121-
cause = x.getCause();
122-
} else {
123-
cause = x;
124-
}
125-
logger.error("Unable to start: {}", mainClass, cause);
119+
logger.error("Unable to start: {}", mainClass, withoutReflection(x));
126120
} finally {
127121
Thread.currentThread().setContextClassLoader(contextClassLoader);
128122
}
@@ -138,6 +132,12 @@ public void close() {
138132
closeServer();
139133
}
140134

135+
private Throwable withoutReflection(Throwable cause) {
136+
while(cause instanceof ReflectiveOperationException) {
137+
cause = cause.getCause();
138+
}
139+
return cause;
140+
}
141141
private void unloadModule() {
142142
try {
143143
if (module != null) {
@@ -219,7 +219,7 @@ public void start() throws Exception {
219219
try {
220220
logger.debug("project: {}", toString());
221221

222-
ModuleFinder[] finders = finders(false);
222+
ModuleFinder[] finders = {new FlattenClasspath(projectName, resources, dependencies)};
223223

224224
ExtModuleLoader loader = new ExtModuleLoader(finders);
225225
module = new AppModule(logger, loader, projectName, mainClass, executionMode,
@@ -261,13 +261,6 @@ private DirectoryWatcher newWatcher() throws IOException {
261261
.build();
262262
}
263263

264-
private ModuleFinder[] finders(boolean flatten) {
265-
if (flatten) {
266-
return new ModuleFinder[]{new FlattenClasspath(projectName, resources, dependencies)};
267-
}
268-
return new ModuleFinder[]{new ProjectClasspath(projectName, resources, dependencies)};
269-
}
270-
271264
@Override public String toString() {
272265
StringBuilder buff = new StringBuilder();
273266
buff.append(projectName).append("\n");

modules/jooby-run/src/main/java/io/jooby/run/ProjectClasspath.java

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)