Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Lessons Learned from Building Spring Tooling for Eclipse Martin Lippert @martinlippert
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 4 AJDT Groovy-Eclipse
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 5 AJDT Groovy-Eclipse Grails IDE
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 6 AJDT Groovy-Eclipse Grails IDE Gradle Integration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 7 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 8 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 9 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted Cloud Foundry Integration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 10 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted Flux Cloud Foundry Integration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 11 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted Flux Cloud Foundry Integration tc Server Integration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 12 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted Flux Cloud Foundry Integration tc Server Integration Spring Roo
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring IDE 13 AJDT Groovy-Eclipse Grails IDE Gradle Integration Spring Tool Suite Scripted Flux Cloud Foundry Integration tc Server Integration Spring Roo dm Server Integration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 15 Lets Copy JDT and add AspectJ stuff to it - which actually makes a lot of sense -
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Ok, but… • copying code is almost always a bad idea • doesn’t work for all cases • imagine running a true re-packaged copy of JDT alongside JDT • duplicated menu entries, actions • you want just one “open type” dialog • that shows java types AND aspect types 16
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Lets modify JDT on the fly
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ weave code into JDT • lets do the strangest thing that you could possibly imagine: • lets modify JDT code at class-loading time • hack into the Equinox runtime to do that • use AspectJ aspects to do that (using Equinox AspectJ Weaving technology) 18
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ weave code into JDT - pros and cons • works surprisingly well • code doesn’t change that often • Equinox team keeps old hook API available (huge thanks to Tom Watson!!!) • works even with feature patches for JDT • but it is shooting with a big weapon at a small problem • test setup becomes a nightmare • you end up writing IDE plugins to deal with these nightmares 19
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ how to implement Groovy tooling for Eclipse? • lets create a fork of JDT that supports Java and Groovy compilation • that is great, because: • incremental compilation • great integration into Eclipse • nice design in the background: • map language constructs from Groovy to the JDT model • inject the right language tools into the compiler pipeline • would easily allow you to add another language like Scala • compiler would be able to mix-match all those languages 21
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ feature patching JDT • since it is a hacked JDT, you can’t have that co-exist with JDT • you need to replace the original JDT with the hacked version • solution: create and ship a feature-patch for JDT • welcome to hells kitchen • you need to merge new JDT versions into the fork (not fun) • you need to make sure people can’t install the hacked JDT on a newer JDT (or maybe they should?) • you can’t use multiple JDT feature patches at the same time • we had to patch the Groovy compiler, too (recoverable parser) • patching becomes nightmare 22
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ advice • if you end up patching something like JDT • ==> fully automate this process 23
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ hacking the JDT to support another or multiple languages kills you 24
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ the issues summarized • hacking JDT was a bad idea • weaving works, but doesn’t make a lot of sense • feature-patching JDT works, but causes a lot of pain • copying JDT works, but also causes a lot of pain • some languages come with compilers, parsers, linters, etc. out of the box • why re-implement everything in Java/Eclipse? 25
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ re-implementing language tooling in Eclipse is hard 26
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ but what to do instead? 27
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ external language tooling • separate processes • language server protocol • communication via JSON • re-use what is there (in whatever language it is written) • this is not without its own challenges • e.g. error-recovering parsers • protocol limitations • JSON overhead 28
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ understand the Spring app • try to “understand” the spring app in your workspace projects • to provide validations • content-assist • quick-fixes • navigation • etc. • how can you do that? 30
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ parse the code • analyze source and compiled code (re-use Java model from JDT maybe) • build up a model of the “Spring elements” of that code • re-implement the Spring framework mechanics to figure out what those code elements actually mean • what defines a bean? • what beans are around? • how are beans wired? • You end up re-implementing a lot of the logic of the Spring framework • You need to adapt that to newer versions of Spring • You need to write that for third-party extensions 31
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ re-use Spring • re-use Spring itself to do all the work • call the Spring framework itself • feed it with the project • ask it for the results • adapts to new Spring versions automatically • is more exact than anything else • no duplicate Spring logic • works out-of-the-box for third-party extensions and add-on Spring projects • all great, eh? 32
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ the problematic parts • Spring analyzes class files and loads them into the JVM • that means to load project code into the IDE JVM (per project) • needs to be isolated • uses specialized class loader hackery • you mix and match Spring framework code from the IDE and the project • for example: • the IDE comes with Spring 4.3.0, the app uses Spring 5.0.0.M1 33
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ IDE 34 spring beans 4.3.0 ide.core spring context 4.3.0
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ project 35 .class spring beans 5.0 spring context 5.0 spring boot 2.0 spring cloud 2.1 IDE spring beans 4.3.0 ide.core spring context 4.3.0
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ project IDE 36 spring beans 4.3.0 ide.core .class spring beans 5.0 spring context 4.3.0 spring context 5.0 project classloader spring boot 2.0 spring cloud 2.1 creates
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ project IDE 37 spring beans 4.3.0 ide.core .class spring beans 5.0 spring context 4.3.0 spring context 5.0 project classloader spring boot 2.0 spring cloud 2.1 bundle classloader parent
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ project IDE 38 spring beans 4.3.0 ide.core .class spring context 4.3.0 project classloader spring boot 2.0 spring cloud 2.1 bundle classloader parent
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusions • loading user code into the IDEs JVM is a really really really bad idea • static initializers run • can crash the IDEs JVM • fills up memory / class space • need to cleanup very carefully to allow GCs • you can’t keep up with the update speed of Spring project versions • errors become a nightmare to debug • no easy workarounds possible 39
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Instead • do source/code analysis instead • or run things in separate processes 40
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ why using Spring libs as OSGi bundles kills you over time 41
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring libraries as OSGi bundles • Spring library JARs have hundreds of dependencies • most of them are optional (which is good) • but you don’t know which ones are optional for your case and which ones are not • the Spring OSGi bundles heavily use package-use constraints • good for consistency • bad for performance • extremely complicated to ensure a consistent set of bundles 42
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ “just did an update from STS 3.8.1 to 3.8.2” org.osgi.framework.BundleException: Could not resolve module: org.springframework.ide.eclipse.boot.dash [1634] Bundle was not resolved because of a uses contraint violation. org.osgi.service.resolver.ResolutionException: Uses constraint violation. Unable to resolve resource org.springframework.ide.eclipse.boot.dash [osgi.identity; osgi.identity="org.springframework.ide.eclipse.boot.dash"; type="osgi.bundle"; version:Version="3.8.2.201610040608-RELEASE"; singleton:="true"] because it is exposed to package 'javax.xml.ws.handler' from resources org.eclipse.osgi [osgi.identity; osgi.identity="org.eclipse.osgi"; type="osgi.bundle"; version:Version="3.10.102.v20160118-1700"; singleton:="true"] and javax.xml.ws [osgi.identity; osgi.identity="javax.xml.ws"; type="osgi.bundle"; version:Version="2.1.0.v200902101523"] via two dependency chains. Chain 1: org.springframework.ide.eclipse.boot.dash [osgi.identity; osgi.identity="org.springframework.ide.eclipse.boot.dash"; type="osgi.bundle"; version:Version="3.8.2.201610040608-RELEASE"; singleton:="true"] require: (osgi.wiring.bundle=org.eclipse.core.runtime) | provide: osgi.wiring.bundle: org.eclipse.core.runtime org.eclipse.osgi [osgi.identity; osgi.identity="org.eclipse.osgi"; type="osgi.bundle"; version:Version="3.10.102.v20160118-1700"; singleton:="true"] Chain 2: org.springframework.ide.eclipse.boot.dash [osgi.identity; osgi.identity="org.springframework.ide.eclipse.boot.dash"; type="osgi.bundle"; version:Version="3.8.2.201610040608-RELEASE"; singleton:="true"] require: (osgi.wiring.bundle=org.springframework.web) | provide: osgi.wiring.bundle; bundle-version:Version="4.3.0.20160611-RELEASE"; osgi.wiring.bundle="org.springframework.web" org.springframework.web [osgi.identity; osgi.identity="org.springframework.web"; type="osgi.bundle"; version:Version="4.3.0.20160611-RELEASE"] import: (&(osgi.wiring.package=javax.xml.ws.handler)(version>=0.0.0)) | export: osgi.wiring.package: javax.xml.ws.handler javax.xml.ws [osgi.identity; osgi.identity="javax.xml.ws"; type="osgi.bundle"; version:Version="2.1.0.v200902101523"] at org.eclipse.osgi.container.Module.start(Module.java:434) at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1582) at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1561) 43
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusions • if you ever want to use a Spring library in an IDE plugin for Eclipse • DO NOT re-use the OSGi-bundles • INSTEAD embed the Spring libs (with their dependencies) inside of bundles (static linking) • yes, I know, this is the dark side of reuse • works within a bundle, not nicely across bundle boundaries • you could export those packages, but that opens the door to trouble again • but it is definitely the less painful way 45
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Cloud IDEs at the horizon • we want to move to the cloud (somehow, somewhere) • lets build services that we can re-use • lets build UIs that we can re-use 47
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Re-usable UI components • lets use HTML5/CSS/JavaScript to build UIs • use them for web front-ends • embed them into Eclipse/STS • Embed HTML5/CSS components into SWT-based UIs? • Yeah, that is possible and should be straight forward… 48
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ HTML inside of Eclipse IDE 49
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Well, it is not… • embedded browser • which technology is being used under the hood? • works with OSX • needs a specific flag on Windows (to get the right version of IE on board) • was horrible in Linux 50
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ JavaFX browser component instead? • cool, cross-platform engine, webkit-based • JavaFX-SWT bridge does exist (+ e(fx)clipse runtime) • works nicely, but on a certain Java level only • UI doesn’t really integrate into SWT (looks different) • sometimes quite slow • does Oracle takes care of new webkit versions for JavaFX? • it is (again) a strange combination of technologies 51
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Oh… and it kills your battery… 52
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusions • do not mix UI technologies • we will try to get rid of those UIs again • we will continue to use purely SWT-based UIs in Eclipse • focus on re-usable parts below the UI • tooling as a service • (even as external processes) 53
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Lets configure STS remotely 54
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Remote Properties • Lets enable/disable certain features via properties • Lets load those properties from a remote location to enable/disable those features from our servers 55
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ And you are right back in hell… • the network is accessed as soon as the first one needs that property • on random threads • in random situations • blocks UI in weak network settings 56
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Conclusions • Be really really careful when doing network access • do not rely on this information • have default behavior in place • react to feedback when remote properties become available 57
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Hope you enjoyed the ride 58
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Learn More. Stay Connected. @springcentral spring.io/blog @pivotal pivotal.io/blog @pivotalcf http://engineering.pivotal.io