Saturday, March 4, 2017, 2:16:53 AM, Daniel Dekany wrote: [snip] > I don't think that activating a FreeMarker extension merely based on > its presence in the class path is acceptable, for most kind of > extensions. Real world projects easily use 100+ dependencies, most of > them being transitive (so you have never asked for them explicitly), > so practically, whether a particular jar (like freemarker-dom) appears > in the class path is out of your control. > > The valid cases for automatically activating extensions are when > without the extension you simply ran into an error. Like FreeMarker > wants to wrap a java.time class, but freemarker-core-java-8 is > missing, that's an error, so we should auto-discover[*] that extension. > But with freemarker-dom, you can wrap DOM nodes without it, only they > will look different (like regular beans). So this extensions doesn't > prevent an error, but alters behavior, and thus I believe it must be > activated explicitly, independently for each Configuration. [snip] > *: Auto discovering of freemarker-core-java-8 is actually a special > case, because freemarker-core already knows about it and looks for > it itself (pull VS push basically). Because, it has to know that > seeing a java.time object but not freemarker-core-java-8 is an > error.
I'm fiddling with the modularization (using Gradle 3.5), and avoiding circular dependencies between freemarker-core-java-8 and freemarker-core leads to quite monstrous solution. The way it works (in FM2) is that there's a freemarker.core._Java8 interface compiled with Java 7, which is implemented by freemarker.core._Java8Impl that is compiled with Java 8. That works for Ant and on runtime, but no IDE supports having files with different Java versions inside the same "project" (module in IntelliJ), and the same looks like a problem (but at least a big hack to achieve) for Gradle as well. So the idea was that we bite the bullet and add a freemarker-core-java-8 module (a separate jar), which we build with Java 8, and freemarker-core, which we build with Java 7, depends on that. Nice and clean. Except, in which module do you have the freemarker.core._Java8 interface then? If in freemarker-core, you have a circular dependency (because freemarker-core-java-8 implements the _Java8 interface, so it must depend on freemarker-core). If in freemarker-core-java8, then the class will be compiled to Java 8 class format so the JVM will fail to load the interface on Java 7. So in theory we have to add a third module (jar), freemarker-core-java-adapte, which contains the _Java8 interface (and later _Java9, etc.) compiled with Java 7. Then freemarker-core-java-8 depends on that instead of freemarker-core, and freemarker-core just depends on freemarker-core-java-8 as planned (and gets the freemarker-core-java-adapter dependency transitively). Yeah... add to this that at the moment all we have in _Java8 is `boolean isDefaultMethod(Method)`. It will certainly expand in the future, but still. Madness. But it gets funnier. Where do I put the Java 8 unit tests? You would think that the right place is freemarker-core-java8. But nope, because the tests aren't much about testing _Java8Impl, but the behavior of FreeMarker itself when it meets Java 8 default methods and such. So obviously the tests depend freemarker-core, a circular module dependency again (Gradle might understands that it's not really that, as its just a dependency of the tests, but Eclipse certainly doesn't), and anyway you are really testing freemarker-core. So let's put it there. But you have to compile and run these tests on Java 8, so you again get a module that uses multiple JDK-s, even if the split is at least between the "main" and test part (though ideally you run all the other tests on Java 7). So clearly, you need a separate freemarker-core-java8-test module... 4 modules so far (to call isDefaultMethod for now). I'm very tempted to go for a reflection hack inside freemarker-core, but that won't "scale" well if more complex stuff, like Java 8 time API support will appear, and who knows what later Java versions will bring. Any ideas? -- Thanks, Daniel Dekany
