Review First Java9 Migration Attempt

Yesterday i had looked what happens if i build AssertJ with the current Java9 (1.9.0-ea-b66) release and stumbled upon some things which i had not expected. To be true here i had expected that everything works fine. Mainly because AssertJ has almost no dependencies and does not use some fancy stuff like Unsafe. Maybe i was too optimistic. ;)

Problem 1: Compiler error with bounded generics with arrays/varargs

The first problem involves a specific combination of

and appears as a compiler error. Consider the following example which works fine with the latest Java8 (1.8.0_45-b14).

 1 public class Example {
 2     @SafeVarargs
 3     public static <T> A<T> create(A<? extends T>... a) {
 4         return allOf(a);        //Compile error
 5     }
 6 
 7     @SafeVarargs
 8     public static <T> A<T> allOf(A<? extends T>... a) {
 9         return null;
10     }
11 
12     class A<T> {}
13 }
 1 de/bischinger/jdk9test/Example.java:11: error: method allOf in class
 2  Example cannot be applied to given types;
 3         return allOf(a);
 4                ^
 5   required: Example.A<? extends T#1>[]
 6   found: Example.A<? extends T#2>[]
 7   reason: cannot infer type-variable(s) T#1
 8     (varargs mismatch; Example.A<? extends T#2>[] cannot be converted
 9      to Example.A<? extends T#1>)
10   where T#1,T#2 are type-variables:
11     T#1 extends Object declared in method <T#1>allOf(Example.A<? extends T#1>...)
12     T#2 extends Object declared in method <T#2>create(Example.A<? extends T#2>...)
13 1 error

As the error message points out (with -Xdiags:verbose) Java9 is more strict when it comes to such constellations. I am not sure why this change was really necessary but it probably came with JEP-213.

Solution or Workaround?

The only workaround to that problem i was able to found looks as follows

1 public static <T> A<T> create(A<? extends T>... a) {
2             return Example.<T>allOf(a);
3     }

and looks ugly. The thing which makes it more ugly is that this cannot be done with an automatic refactoring via an IDE. ;(

Problem 2: XML PrettyPrint

The other thing i had found is that the behavior of XML pretty print does not work anymore. At first this does not sound like a problem but if your software is using this functionality and makes use of equals (which testing frameworks or tests sometimes do) then you probably have a problem.

At the moment i have not found a solution/workaround for it. So if you have any information about that please let me know.

 1 public class PrettyPrint {
 2     public static void main(String[] args) throws Exception {
 3         String xml = "<rss version=\"2.0\"><channel>  <title>Java Tutorials and Examples 1</title>  <language>en-us</language></channel></rss>";
 4         Writer stringWriter = createPrettyPrint(xml);
 5         System.out.println(stringWriter.toString());
 6     }
 7 
 8     private static Writer createPrettyPrint(String xml) throws Exception {
 9         DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
10         DOMImplementationLS domImplementation = (DOMImplementationLS) registry.getDOMImplementation("LS");
11         Writer stringWriter = new StringWriter();
12         LSOutput formattedOutput = domImplementation.createLSOutput();
13         formattedOutput.setCharacterStream(stringWriter);
14         LSSerializer domSerializer = domImplementation.createLSSerializer();
15         domSerializer.getDomConfig().setParameter("format-pretty-print", true);
16         // Set this to true if the declaration is needed to be in the output.
17         domSerializer.getDomConfig().setParameter("xml-declaration", true);
18         domSerializer.write(toXmlDocument(xml), formattedOutput);
19         return stringWriter;
20     }
21 
22     private static Document toXmlDocument(String xmlString) throws Exception {
23         InputSource xmlInputSource = new InputSource(new StringReader(xmlString));
24         DocumentBuilder xmlDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
25         return xmlDocumentBuilder.parse(xmlInputSource);
26     }
27 }

Java9

1 <?xml version="1.0" encoding="UTF-8"?><rss version="2.0">
2     <channel>  <title>Java Tutorials and Examples 1</title>  <language>en-us</language>
3     </channel>
4 </rss>

Java8

1 <?xml version="1.0" encoding="UTF-8"?>
2 <rss version="2.0">
3     <channel>
4         <title>Java Tutorials and Examples 1</title>
5         <language>en-us</language>
6     </channel>
7 </rss>