Wiki

Clone wiki

syntactic / ConvertingJava8To7

Converting Java 8 to 7

How to use Syntactic to convert Java 8 syntax into Java 7 syntax

Caveats

  • Not all Java 8 features are supported
  • Those features that are supported, are not supported in full
  • There are currently some limitations around nesting of features (e.g. Lambdas inside lambdas)
  • There are some limitations resolving imports of nested classes
  • Error handling is minimal - if your code is not valid, then you may receive abstruse error messages
  • The tool to call the converter is missing features

Supported Features

Lambda expressions

Lambda expressions are supported in a variable declaration

e.g.

Runnable runnable = () -> { System.out.println("Running!"); } ;

String str = "abc";
Callable<String> callable = () -> str ;

FileFilter filter = (file) -> file.getName().endsWith(".xml") ;

javax.swing.event.ChangeListener listener = event -> { System.err.println("Event:" + event); };

Comparator<? super String> cmp = (CharSequence a, CharSequence b) -> { 
    Integer l1 = a.length(), l2 = b.length();
    return l1.compareTo(l2);
};

As you can see from the examples above the following are supported:

  • Block based lambdas (runnable, listener and cmp)
  • Expression based lambdas (callable and filter)
  • Zero-argument lambdas (runnable and callable)
  • The parenthesis-less syntax for single-argument lambdas (listener)
  • Implied argument types (filter, listener)
  • Generics (callable and cmp)
  • Generics with wildcards (cmp)
  • Effectively final variables (str in callable)

The resulting Java 7 code for these statements is:

Runnable runnable = new Runnable() {
    public void run() { System.out.println("Running!"); }
};

final String str = "abc";
Callable<String> callable = new Callable<String>() {
    public String call() throws java.lang.Exception { return str; }
};

FileFilter filter = new FileFilter() { 
    public boolean accept(java.io.File file) { return file.getName().endsWith(".xml"); }
};

javax.swing.event.ChangeListener listener = new javax.swing.event.ChangeListener() {
    public void stateChanged(javax.swing.event.ChangeEvent event) { System.err.println("Event:"+event); }
};

Comparator<? super String> cmp = new Comparator<CharSequence>() {
    public int compare(CharSequence a, CharSequence b) {
        Integer l1 = a.length(), l2 = b.length();
        return l1.compareTo(l2);
    }
};

Method and Constructor references

Method references and constructor references are supported in a variable declaration.

e.g.

Callable<String> c = this::toString;
ChangeListener listener = ChangeEvent::toString;
Runnable runnable = MyClass::execute;
Callable<Date> cd = Date::new;
Factory<?, String> factory = Date::new;

The following are supported:

  • Bound instance methods (c)
  • Unbound instance methods (listener)
  • Static methods (runnable)
  • Constructors (cd and factory)

The resulting Java 7 code for these statements is:

Callable<String> c = (new Callable<String>() { 
    public String call() throws java.lang.Exception { return this.toString(); }
});
ChangeListener listener = (new ChangeListener() {
    public void stateChanged(javax.swing.event.ChangeEvent arg0) { arg0.toString(); }
});
Runnable runnable = (new Runnable() {
  public void run() { MyClass.execute(); }
});
Callable<Date> cd = (new Callable<Date>() {
  public Date call() throws java.lang.Exception { return new java.util.Date(); }
});
Factory<?, String> factory = (new Factory<Object, String>() {
  public Object create(String arg) { return new java.util.Date(arg); }
});

Other lambda expressions

Lambda expressions outside of a variable declaration are not supported, but will be in the future.

Other Method and Constructor references

Method references and constructor references outside of a variable declaration are not supported, but will be in the future.

Unlikely to be Supported Features

Default methods

Default methods may be supported in some limited fashion in the future, but are unlikely to be supported in full.

Collections Framework Changes

The converter handles syntax changes only, and does not provide a backwards-compatible class library.

The Conversion Tool

Executing

The conversion tool is in org.adjective.syntactic.convert.j8to7.Main.

It takes the following command line arguments

  • --source is a file to be converted, or a directory to be recursively converted
  • --output is the file or directory where the conversion output should be saved
  • --classpath is a standard java classpath for the loading of references classes (in particular the functional interfaces used in the code being converted)
  • --flatten prevents the tool from recreating the source directory structure under output

It requires three jar files on the classpath:

e.g.

java -cp syntactic-parser.jar:syntactic-convert.jar:args4j.jar org.adjective.syntactic.convert.j8to7.Main --source src/com/example/MyClass.java --output .

Limitations

The tool can load references classes from the provided classpath or from within the same compilation unit. It is not currently capable of loading references classes from the sourcepath (i.e. the list of files to be converted)

Updated