Are there specific Java9 JRE classes that we should focus on to get into GWT?
Would making GWT support Java9 sources and running in a Java9 env cause backward incompatible changes that prevent GWT from running in Java8?
So, to be pedantic:Language features -> no issues there at all, since JDT happily compiles java 8 code w/ a java 9-compatible compiler.Emul updates -> standard "don't use java 9 methods if you need java 8 support"
Classpathery -> Made it use ugly reflection to not require java 9 classes on classpath; it does require more opening of modules and ugliness, but ensures that we don't break when using java 8.
I'm actually using the java 9 compatible version of gwt daily in java 8 code.we could make the classpath nastiness a little better using sane feature detection and loading classes that don't need (as much) reflection to be able to extract the URLs from java 9 classloader......however, long term, I still think that we should reconsider how ResourceLoader works, and possibly consider something that accepts classpaths as arguments. It's fairly trivial to have arbitrary java code use maven to cache/download dependencies, so we could, technically, get classpath into Gwt without relying on classloader scanning.
That would be a broader discussion to have though.
The one big caveat is code modularity. We can't release two jars with code in the same packages (unless recent changes to module system now allowed "concealed package conflicts").
So, that means either one big, ugly uber-jar for compilation (my hack unzips gwt-user and gwt-dev locally to avoid these issues)... or we actually, finally modularize the codebase.
Could that work if we complemented the "instanceof URLClassLoader" with some check for "is the system classloader" and then use System.getProperty("java.class.path") (or the equivalent ManagementFactory.getRuntimeMXBean().getClassPath()) to get the system classpath entries? (do we also need the bootclasspath?)
String java9Modules = System.getProperty("gwt.java9.modules");
for (ClassLoader candidate = wrapped; candidate != null; candidate = candidate.getParent()) {
if (candidate instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) candidate).getURLs()) {
result.put(url.toExternalForm(), url);
}
} else if (java9Modules != null) {
// If the user specified java 9 modules to load for classpath,
// we'll want to do it all through reflection,
// to avoid losing support for java 8
try {
final Class<?> modRef = candidate.loadClass("java.lang.module.ModuleReference");
final Method getLocation = modRef.getMethod("location");
// In the case of java 9, the only way to scrape classloaders is this ugly reflection
// on an internal class (used to be a URLClassLoader).
// you will need to add `--add-opens java.base/jdk.internal.loader=myJava9ModuleName`
// to your gwt runtime as a VM argument
final Class<?> loader = candidate.loadClass("jdk.internal.loader.BuiltinClassLoader");
// TODO: Don't use classloader for resource loading
final Method findMod = loader.getDeclaredMethod("findModule", String.class);
// This is why we have to open the package; just being visible is not enough
// to be allowed to act reflectively
findMod.setAccessible(true);
for (String source : java9Modules.split(",")) {
System.out.println("Loading java 9 module " + source);
Object mod = findMod.invoke(candidate, source);
// Safe to cast; we must be in java 9 to get here,
// so we know that this cast should be safe
Optional<URI> location = (Optional<URI>) getLocation.invoke(mod);
if (location.isPresent()) {
final URL url = location.get().toURL();
result.put(url.toExternalForm(), url);
}
}
} catch (Exception ignored) {
if (ignored instanceof InterruptedException) {
Thread.currentThread().interrupt();
throw new RuntimeException(ignored);
}
ignored.printStackTrace();
}
}
}
IIRC, when CodeServer was added, with its -src argument, I suggested passing classpaths as argument rather than using the system classpath.At the time though, there was even more code that relied on the context classloader than today (rather than using the ResourceOracle). This was fixed later for the most part, but I believe there's still code that uses the context classloader (including looking up annotations from com.google.gwt.core.ext.typeinfo, and AFAIK also JDT loading bytecode that ends up being looked up in the context classloader; see 8b584f412d055ff39949d8b28a8e78d6b0bfe9b6 for example)I suppose that could be fixed by using a child URLClassLoader from the classpath argument (that could be necessary anyway for generators and linkers)
The one big caveat is code modularity. We can't release two jars with code in the same packages (unless recent changes to module system now allowed "concealed package conflicts").IIUC, they say this can be worked around using classloaders, or shading/shadowing (i.e. what you're doing)
So, that means either one big, ugly uber-jar for compilation (my hack unzips gwt-user and gwt-dev locally to avoid these issues)... or we actually, finally modularize the codebase.Does that also apply to subpackage? Because it looks like the only conflicting packages are c.g.g.core.client and c.g.g.core.shared, so maybe moving classes around could be enough?
Could that work if we complemented the "instanceof URLClassLoader" with some check for "is the system classloader" and then use System.getProperty("java.class.path") (or the equivalent ManagementFactory.getRuntimeMXBean().getClassPath()) to get the system classpath entries? (do we also need the bootclasspath?)
Another alternative is to go the way of apt and use something akin to AnnotationMirror... meaning you can't just do MyAnnoClass anno = member.getAnnotation(MyAnnoClass.class), but will instead be stuck operating on a generic mirror which can get members by string name. Not exactly pretty, but if it's good enough for apt, it can clearly be made to work (plus, with the impetus to ditch generators, we'd be stuck with it anyway).
I (also) have another project which converts AnnotationMirror to a proxy of MyAnnoClass that can either load a dependent Class/Enum, or fail if that class is not on classpath (but only fail if you try to access that member).
Fwiw, I think it would work, according to https://github.com/AdoptOpenJDK/openjdk-jdk9/blob/f9129bba032f3b75be9b67f45636f76940e029a6/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java#L70-L73(for now, I'm not interested in supporting modules, just making GWT 2 work in a Java 9 VM)
Another alternative is to go the way of apt and use something akin to AnnotationMirror... meaning you can't just do MyAnnoClass anno = member.getAnnotation(MyAnnoClass.class), but will instead be stuck operating on a generic mirror which can get members by string name. Not exactly pretty, but if it's good enough for apt, it can clearly be made to work (plus, with the impetus to ditch generators, we'd be stuck with it anyway).But isn't the whole issue with annotations due to JDT?
I (also) have another project which converts AnnotationMirror to a proxy of MyAnnoClass that can either load a dependent Class/Enum, or fail if that class is not on classpath (but only fail if you try to access that member).You mean like https://docs.oracle.com/javase/7/docs/api/javax/lang/model/element/Element.html#getAnnotation(java.lang.Class) ?(ok, that one won't load the Class/enum from the classpath, but always throw when accessing members of those types)
It is my understanding that we use ASM to load the annotation attributes from source classes, and then create a Proxy to load member values / classes / enums off the classpath. JDT is not involved at all (strange that it isn't...).
It is my understanding that we use ASM to load the annotation attributes from source classes, and then create a Proxy to load member values / classes / enums off the classpath. JDT is not involved at all (strange that it isn't...).The most likely reason we aren't using JDT to compile the annotaitons is we are really only using the parser, but not the linker (no code to emit classfiles)....
--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/d08d7ad2-4f67-4118-bf81-2924fedfddf3%40googlegroups.com.
I have uploaded two patches for review to allow GWT to run under a Java 9 vm.The main issue is (as noted by James) that the class loading has been revamped and GWT can no longer assume that the class loaders are UrlClassLoaders.The idea is first to be able to run GWT on a Java 9 vm compiling Java 8 sources.
On Wed, Jun 14, 2017 at 3:01 PM, James Nelson <Ja...@wetheinter.net> wrote:
It is my understanding that we use ASM to load the annotation attributes from source classes, and then create a Proxy to load member values / classes / enums off the classpath. JDT is not involved at all (strange that it isn't...).The most likely reason we aren't using JDT to compile the annotaitons is we are really only using the parser, but not the linker (no code to emit classfiles)....
--
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsu...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/CAC7T7gnO-OFBnzEKyoF1mi3W4Tqn%2BjE_CDTrNpGU2i98yKPjhA%40mail.gmail.com.