SlideShare a Scribd company logo
Migrating to Java11
echo 'I am running on Java 8!'|sed s/8/11/g
arto.santala@solita.fi
Who am I?
• Arto Santala
• Work as software architect in Solita, producing tailored
solutions to accelerate customer business
• More than 20 years of experience making customers
dreams come true with application of proper technologies
and methodologies
• Guilty of writing a lot of horrible code in the 90’s that
should be burned with fire. Always aiming to improve.
• Passionate about agile and automation. Trying to make
every moment worthy of living.
Java 8 as platform
• Java 8 is product of more than 20 years of development. Every
release, more and more have been added, nothing has never
been removed
• Today Java 8 is a heavy platform with a lot of libraries that you
will never need
• Midi instruments, 1995 version of java.util.Date, Corba IIOP, applets,
AWT, …
• Heavier images, larger memory footprint, more attack area for
vulnerabilities
Java 8 + Spring Boot Helloworld
Also, Oracle JDK public version is dead by Jan 2019
- No more updates, unless you use some other build/vendor
Java 9 as platform
• Modular JDK, Modular source code, Modular run-time images, Module system, Modular
application packaging, Java platform module system, etc
• Also: Jshell, new HTTP client (HttpRequest/HttpResponse), Process API, Pub/Sub
framework, immutable set/list, Optional to Stream, etc
module fi.solita.java9training.api {
requires fi.solita.java9training.services;
exports fi.solita.java9training.api;
}
Set<String> mySet = Set.of(”val1", ”val2", ”val3");
List<String> myList = List.of(”val1”,”val2”,”val3”);
Java 10 as platform
• Not such a revolution, just a bit of evolution
• Hard transition from Java 8 to Java 9
• Easy transition from Java 9 to 10 and 11
• GA is out there now – but do note the short support lifetime for both Java 9 and 10
var item1 = ”HELLO”;
var list1 = List.of(item1,”WORLD”);
Java 11 as platform
• Local-variable syntax for Lambda parameters (JEP 323)
• Epsilon Garbage Collector (JEP 318, , only handles allocation, does not reclaim memory)
• ZGC (JEP 333, low-latency scalable garbage collector, experimental)
• Dynamic class-file constants (JEP 309)
• A lot of removed modules, for example Java EE,Corba,Nashorn,Pack200 tools&API (Need
to bring in as dependencies)
• Unicode v10 Support
• New http client model
• LTS Release, best support
• Oracle, OpenJDK, RedHat, Zuul, etc
https://www.oracle.com/technetwork/java/javase/11-relnote-issues-5012449.html
Migrating to Java 11
Migrating to Java 11
Really, why would I migrate?
• Next LTS version (if you own a commercial
license)
• Full support for Linux containers (Docker aware)
• Support parallel full garbage collection on G1
• New ZGC and Epsilon garbage collectors
• Free Application Class-Data Sharing feature
• Free low overhead Flight Recorder and Heap
Profiler
• Heap allocation on alternative memory devices
• New default set of root authority certificates
• Ahead-of-time compilation and GraalVM
• Transport Layer Security (TLS) 1.3
• Multi-release JARs.
• JShell
• Support for “shebang” Java files! #!/bin/java
• Support for HTTP 2.0 with new async client
• New native unmodifiable collections APIs.
• New reactive streams APIs.
• Improved streams/predicate/optional APIs.
• Improved system process API.
• Now you can var!
• Module system – Modular JRE – Modular libraries
• All the bugfixes and security patches
• Libraries that survive the migration are stronger
(Darwin)
• Bragging rights!
Java 11 + Spring Boot Helloworld
Still fat, but getting better!
Pssst, minimal Java 11 + Apache Spark web services
JSHELL REPL
JLINK
jlink --module-path $JAVA_HOME/jmods --verbose --add-modules
java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.man
agement,java.security.jgss,java.instrument --compress 2 --no-header-files --output jdk-9-
minimal-osx --no-man-pages
Jlink is a new tool that allows to link modules and even JRE together as a platform specific
executable.
For example, you can generate a custom JRE with just the modules you need to run Spring
Boot, like this:
Much less attack surface, less to update, less disk use, less memory use, faster startup, etc
Java Support Roadmap
http://www.oracle.com/technetwork/java/eol-135779.html
Support/JDK Brand options
• Oracle (Commercial+Trialing)
• OpenJDK (Go crazy, no support for past versions)
• Azul (Commercial)
• IBM (Commercial, own builds, own patches)
• RedHat (Mainly LTS versions)
• AdoptOpenJDK (Go crazy!)
• …
https://blog.joda.org/2018/09/time-to-look-beyond-oracles-jdk.html?m=1
Maven source level
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
Maven compiler plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<release>10</release>
</configuration>
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>

<version>6.1.1</version>
</dependency>
</dependencies>
</plugin>
Quick (stupid) test
@RestController
public class HelloController {
@RequestMapping(method = RequestMethod.GET)
public Map getGreeting() {
var now = Instant.now();
return Map.of("message", String.format("It's %s", now));
}
}
Typical pitfalls with Java 11
• package javax.xml.bind.annotation.adapters is not visible
• Missing files from java.activation, java.transaction, java.xml.bind, etc
• More and more core modules are missing from core of core, so you should simply add them as new
dependencies
• Illegal reflective access by org.springframework.cglib.core.ReflectUtils
• Java 11 is starting to be more precise on accessing non-public APIs, so primarily you should find libraries
that are not accessing internal APIs
• Ironically, with Spring you can make this warning go away by setting –illegal-access=deny
• In some cases. as short-term solution you can also play with --add-
exports $module/$package=$readingmodule and --add-opens $module/$package=$readingmodule to
open up types and members for deep reflection of also private internals
• So mostly, just make sure dependencies and modules are declared properly, and find libraries
that play nicely with Java 9/10/11 and do not leverage the deprecated internals
• In future, more and more modules and packages will go out of core, so get used to this
Typical pitfalls with Java 11
• Issues with bytebuddy/ASM/cglib/javassist/sun.misc.Unsafe
• sun.misc.Unsafe has been removed, and introspection rules have been tightened
• Pretty much all com.sun and sun.misc packages and utils have been now removed, and you
should simply not use libraries that depend on them. There are new ways to do some of the thing
• Cglib/javassist tools used these a lot so any libraries that depend on them are prone to breaking. In
common any introspection/mock/proxy libraries will easily break.
• Fist attempt is always to see if you can update lib to latest, in some cases you can also update the
dependency within lib to latest javassist/cglib and that resolves the issue
Typical pitfalls with Java 11
• IllegalArgumentException at testCompilation/test phase
• Maven compiler/surefire might be using older version of ASM, which can be fixed like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<release>11</release>
</configuration>
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>6.1.1</version> 
</dependency>
</dependencies>
</plugin>
Other non-default (EE) modules
• java.activation with javax.activation package
• java.corba with javax.activity, javax.rmi, javax.rmi.CORBA, andorg.omg.* packages
• java.transaction with javax.transaction package
• java.xml.bind with all javax.xml.bind.* packages
• java.xml.ws with javax.jws, javax.jws.soap, javax.xml.soap, and alljavax.xml.ws.* packages
• java.xml.ws.annotation with javax.annotation package
• Java 11 will remove all these, so it will not be enough to just --add-modules forever, you
need to find the actual libraries and declare as real, external dependencies
XML modules will go out from core
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
Evaluating old code
• java --list-modules
• jdeps --jdk-internals -R --class-path 'libs/*' $project
• jar –file=mylib.jar --describe-modules
• To figure out automatic module name for the .jar
Illegal access
• --illegal-access=$value option, where $value can be:
• permit: Access to all JDK-internal APIs is permitted to code on the class path. For reflective access,
a single warning is issued for the first access to each package. (Default is Java 9, but will be
removed in a future release.)
• warn: Behaves like permit but a warning is issued for each reflective access.
• debug: Behaves like warn but a stack trace is included in each warning.
• deny: The option for those who believe in strong encapsulation:
• All illegal access is forbidden by default.
Easy migration path/checklist
1) Update essential libraries and tools to absolute latest available versions. This includes
especially Spring Boot (2.1 is preferred version, when available)
2) Testing tools are especially prone to breaking due to using introspection, so for Junit and
Mockito etc go for very latest available
3) Create a copy of the project and local environment, with latest Java version, see if it compiles
4) When it does not, investigate and resolve error messages. They are probably due to libraries
attempting to access parts that are now removed/forbidden
5) Resolve these issues by bringing in removed dependencies separately, updating libraries to
latest versions, or in some case replacing libraries with ones that work with Java 11
6) Try to run it in latest Java. When it fails to run, fix more dependencies.
7) When it starts to run with some errors, you can investigate what you can do with these. These
are typically caused by introspection warnings, and in some cases can be resolved just by
denying any introspection
8) Start enjoying all the cool stuff, modularize to your hearts content, go crazy, go wild, go long!
Typical pitfalls with Spring Boot 2
• Security module has changed a lot: Now you only get what you declare, unlike previously
when there were a lot of defaults
• Spring Data APIs have changed a lot: Now there’s a lot more of Optional use for return
values, and more descriptive names for methods
• Later version of Flyway, not checksum compatible with old version possibly
• References to old versions of Spring modules, or third party modules that depend on 1.x
versions
Docker
• Docker is a lovely way to start experimenting with Java 11/12 without installing it on your own
machine
• docker run -it solita/jdk11
• docker run -it solita/jdk12-ea
• You can map folders to Docker so you can access files in them, such as .jar files, libraries, etc –
you can also expose ports where services run to host machines
• docker run -it -p 8080:8080 -v `pwd`:/root solita/jdk10
• This is just an example, you can take a look and create your own docker images
• How about two-phased Docker image, one step will build the modular JRE, second will package
your .jar with it?
Two-phase dockerfile example
FROM solita/jdk11 as packager
# First stage: JDK 11 with modules required for Spring Boot
RUN /opt/jdk-11/bin/jlink 
--module-path /opt/jdk-10/jmods 
--verbose 
--add-modules
java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.secu
rity.jgss,java.instrument 
--compress 2 
--no-header-files 
--output /opt/jdk-11-minimal
# Second stage, add only our custom jdk distro and our app
FROM solita/jdk11
COPY --from=packager /opt/jdk-11-minimal /opt/jdk-11-minimal
COPY target/*.jar /opt/
ENV JAVA_HOME=/opt/jdk-11-minimal
ENV PATH="$PATH:$JAVA_HOME/bin"
EXPOSE 8080
CMD java -jar /opt/*.jar
Solita resources
• https://github.com/crystoll/spring-boot-java10/
• http://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html
• http://dev.solita.fi/2018/03/02/Update-to-Java11.html
• https://hub.docker.com/r/solita/jdk11/
• https://hub.docker.com/r/solita/jdk12-ea/
Other Resources
• https://blog.jetbrains.com/idea/2018/09/using-java-11-in-production-
important-things-to-know/
• https://hub.docker.com/_/openjdk/
• https://stackoverflow.com/questions/48204141/replacements-for-
deprecated-jpms-modules-with-java-ee-apis/
• https://blog.frankel.ch/migrating-to-java-9/1/
• https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9
• https://github.com/dsyer/spring-boot-java-9
• https://medium.com/criciumadev/its-time-migrating-to-java-11-5eb3868354f9
Thanks!
ARTO SANTALA
Software Architect
arto.santala@solita.fi
+358505747452
Migrating to Java 11

More Related Content

Migrating to Java 11

  • 1. Migrating to Java11 echo 'I am running on Java 8!'|sed s/8/11/g arto.santala@solita.fi
  • 2. Who am I? • Arto Santala • Work as software architect in Solita, producing tailored solutions to accelerate customer business • More than 20 years of experience making customers dreams come true with application of proper technologies and methodologies • Guilty of writing a lot of horrible code in the 90’s that should be burned with fire. Always aiming to improve. • Passionate about agile and automation. Trying to make every moment worthy of living.
  • 3. Java 8 as platform • Java 8 is product of more than 20 years of development. Every release, more and more have been added, nothing has never been removed • Today Java 8 is a heavy platform with a lot of libraries that you will never need • Midi instruments, 1995 version of java.util.Date, Corba IIOP, applets, AWT, … • Heavier images, larger memory footprint, more attack area for vulnerabilities
  • 4. Java 8 + Spring Boot Helloworld Also, Oracle JDK public version is dead by Jan 2019 - No more updates, unless you use some other build/vendor
  • 5. Java 9 as platform • Modular JDK, Modular source code, Modular run-time images, Module system, Modular application packaging, Java platform module system, etc • Also: Jshell, new HTTP client (HttpRequest/HttpResponse), Process API, Pub/Sub framework, immutable set/list, Optional to Stream, etc module fi.solita.java9training.api { requires fi.solita.java9training.services; exports fi.solita.java9training.api; } Set<String> mySet = Set.of(”val1", ”val2", ”val3"); List<String> myList = List.of(”val1”,”val2”,”val3”);
  • 6. Java 10 as platform • Not such a revolution, just a bit of evolution • Hard transition from Java 8 to Java 9 • Easy transition from Java 9 to 10 and 11 • GA is out there now – but do note the short support lifetime for both Java 9 and 10 var item1 = ”HELLO”; var list1 = List.of(item1,”WORLD”);
  • 7. Java 11 as platform • Local-variable syntax for Lambda parameters (JEP 323) • Epsilon Garbage Collector (JEP 318, , only handles allocation, does not reclaim memory) • ZGC (JEP 333, low-latency scalable garbage collector, experimental) • Dynamic class-file constants (JEP 309) • A lot of removed modules, for example Java EE,Corba,Nashorn,Pack200 tools&API (Need to bring in as dependencies) • Unicode v10 Support • New http client model • LTS Release, best support • Oracle, OpenJDK, RedHat, Zuul, etc https://www.oracle.com/technetwork/java/javase/11-relnote-issues-5012449.html
  • 10. Really, why would I migrate? • Next LTS version (if you own a commercial license) • Full support for Linux containers (Docker aware) • Support parallel full garbage collection on G1 • New ZGC and Epsilon garbage collectors • Free Application Class-Data Sharing feature • Free low overhead Flight Recorder and Heap Profiler • Heap allocation on alternative memory devices • New default set of root authority certificates • Ahead-of-time compilation and GraalVM • Transport Layer Security (TLS) 1.3 • Multi-release JARs. • JShell • Support for “shebang” Java files! #!/bin/java • Support for HTTP 2.0 with new async client • New native unmodifiable collections APIs. • New reactive streams APIs. • Improved streams/predicate/optional APIs. • Improved system process API. • Now you can var! • Module system – Modular JRE – Modular libraries • All the bugfixes and security patches • Libraries that survive the migration are stronger (Darwin) • Bragging rights!
  • 11. Java 11 + Spring Boot Helloworld Still fat, but getting better! Pssst, minimal Java 11 + Apache Spark web services
  • 13. JLINK jlink --module-path $JAVA_HOME/jmods --verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.man agement,java.security.jgss,java.instrument --compress 2 --no-header-files --output jdk-9- minimal-osx --no-man-pages Jlink is a new tool that allows to link modules and even JRE together as a platform specific executable. For example, you can generate a custom JRE with just the modules you need to run Spring Boot, like this: Much less attack surface, less to update, less disk use, less memory use, faster startup, etc
  • 15. Support/JDK Brand options • Oracle (Commercial+Trialing) • OpenJDK (Go crazy, no support for past versions) • Azul (Commercial) • IBM (Commercial, own builds, own patches) • RedHat (Mainly LTS versions) • AdoptOpenJDK (Go crazy!) • … https://blog.joda.org/2018/09/time-to-look-beyond-oracles-jdk.html?m=1
  • 18. Quick (stupid) test @RestController public class HelloController { @RequestMapping(method = RequestMethod.GET) public Map getGreeting() { var now = Instant.now(); return Map.of("message", String.format("It's %s", now)); } }
  • 19. Typical pitfalls with Java 11 • package javax.xml.bind.annotation.adapters is not visible • Missing files from java.activation, java.transaction, java.xml.bind, etc • More and more core modules are missing from core of core, so you should simply add them as new dependencies • Illegal reflective access by org.springframework.cglib.core.ReflectUtils • Java 11 is starting to be more precise on accessing non-public APIs, so primarily you should find libraries that are not accessing internal APIs • Ironically, with Spring you can make this warning go away by setting –illegal-access=deny • In some cases. as short-term solution you can also play with --add- exports $module/$package=$readingmodule and --add-opens $module/$package=$readingmodule to open up types and members for deep reflection of also private internals • So mostly, just make sure dependencies and modules are declared properly, and find libraries that play nicely with Java 9/10/11 and do not leverage the deprecated internals • In future, more and more modules and packages will go out of core, so get used to this
  • 20. Typical pitfalls with Java 11 • Issues with bytebuddy/ASM/cglib/javassist/sun.misc.Unsafe • sun.misc.Unsafe has been removed, and introspection rules have been tightened • Pretty much all com.sun and sun.misc packages and utils have been now removed, and you should simply not use libraries that depend on them. There are new ways to do some of the thing • Cglib/javassist tools used these a lot so any libraries that depend on them are prone to breaking. In common any introspection/mock/proxy libraries will easily break. • Fist attempt is always to see if you can update lib to latest, in some cases you can also update the dependency within lib to latest javassist/cglib and that resolves the issue
  • 21. Typical pitfalls with Java 11 • IllegalArgumentException at testCompilation/test phase • Maven compiler/surefire might be using older version of ASM, which can be fixed like this: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <release>11</release> </configuration> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>6.1.1</version> <!-- Use newer version of ASM --> </dependency> </dependencies> </plugin>
  • 22. Other non-default (EE) modules • java.activation with javax.activation package • java.corba with javax.activity, javax.rmi, javax.rmi.CORBA, andorg.omg.* packages • java.transaction with javax.transaction package • java.xml.bind with all javax.xml.bind.* packages • java.xml.ws with javax.jws, javax.jws.soap, javax.xml.soap, and alljavax.xml.ws.* packages • java.xml.ws.annotation with javax.annotation package • Java 11 will remove all these, so it will not be enough to just --add-modules forever, you need to find the actual libraries and declare as real, external dependencies
  • 23. XML modules will go out from core <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency>
  • 24. Evaluating old code • java --list-modules • jdeps --jdk-internals -R --class-path 'libs/*' $project • jar –file=mylib.jar --describe-modules • To figure out automatic module name for the .jar
  • 25. Illegal access • --illegal-access=$value option, where $value can be: • permit: Access to all JDK-internal APIs is permitted to code on the class path. For reflective access, a single warning is issued for the first access to each package. (Default is Java 9, but will be removed in a future release.) • warn: Behaves like permit but a warning is issued for each reflective access. • debug: Behaves like warn but a stack trace is included in each warning. • deny: The option for those who believe in strong encapsulation: • All illegal access is forbidden by default.
  • 26. Easy migration path/checklist 1) Update essential libraries and tools to absolute latest available versions. This includes especially Spring Boot (2.1 is preferred version, when available) 2) Testing tools are especially prone to breaking due to using introspection, so for Junit and Mockito etc go for very latest available 3) Create a copy of the project and local environment, with latest Java version, see if it compiles 4) When it does not, investigate and resolve error messages. They are probably due to libraries attempting to access parts that are now removed/forbidden 5) Resolve these issues by bringing in removed dependencies separately, updating libraries to latest versions, or in some case replacing libraries with ones that work with Java 11 6) Try to run it in latest Java. When it fails to run, fix more dependencies. 7) When it starts to run with some errors, you can investigate what you can do with these. These are typically caused by introspection warnings, and in some cases can be resolved just by denying any introspection 8) Start enjoying all the cool stuff, modularize to your hearts content, go crazy, go wild, go long!
  • 27. Typical pitfalls with Spring Boot 2 • Security module has changed a lot: Now you only get what you declare, unlike previously when there were a lot of defaults • Spring Data APIs have changed a lot: Now there’s a lot more of Optional use for return values, and more descriptive names for methods • Later version of Flyway, not checksum compatible with old version possibly • References to old versions of Spring modules, or third party modules that depend on 1.x versions
  • 28. Docker • Docker is a lovely way to start experimenting with Java 11/12 without installing it on your own machine • docker run -it solita/jdk11 • docker run -it solita/jdk12-ea • You can map folders to Docker so you can access files in them, such as .jar files, libraries, etc – you can also expose ports where services run to host machines • docker run -it -p 8080:8080 -v `pwd`:/root solita/jdk10 • This is just an example, you can take a look and create your own docker images • How about two-phased Docker image, one step will build the modular JRE, second will package your .jar with it?
  • 29. Two-phase dockerfile example FROM solita/jdk11 as packager # First stage: JDK 11 with modules required for Spring Boot RUN /opt/jdk-11/bin/jlink --module-path /opt/jdk-10/jmods --verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.secu rity.jgss,java.instrument --compress 2 --no-header-files --output /opt/jdk-11-minimal # Second stage, add only our custom jdk distro and our app FROM solita/jdk11 COPY --from=packager /opt/jdk-11-minimal /opt/jdk-11-minimal COPY target/*.jar /opt/ ENV JAVA_HOME=/opt/jdk-11-minimal ENV PATH="$PATH:$JAVA_HOME/bin" EXPOSE 8080 CMD java -jar /opt/*.jar
  • 30. Solita resources • https://github.com/crystoll/spring-boot-java10/ • http://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html • http://dev.solita.fi/2018/03/02/Update-to-Java11.html • https://hub.docker.com/r/solita/jdk11/ • https://hub.docker.com/r/solita/jdk12-ea/
  • 31. Other Resources • https://blog.jetbrains.com/idea/2018/09/using-java-11-in-production- important-things-to-know/ • https://hub.docker.com/_/openjdk/ • https://stackoverflow.com/questions/48204141/replacements-for- deprecated-jpms-modules-with-java-ee-apis/ • https://blog.frankel.ch/migrating-to-java-9/1/ • https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9 • https://github.com/dsyer/spring-boot-java-9 • https://medium.com/criciumadev/its-time-migrating-to-java-11-5eb3868354f9

Editor's Notes

  1. https://openjdk.java.net/projects/jdk/12/
  2. If IntelliJ fails to recognize ’var’, you can do File-Invalidate Caches/Restart
  3. You may need to do the same with Surefire plugin
  4. https://stackoverflow.com/questions/49398894/unable-to-compile-simple-java-10-project-with-maven/49398936
  5. https://twitter.com/SolitaOy https://www.facebook.com/Solita https://www.linkedin.com/company/solita-oy/ https://www.youtube.com/user/SolitaOy