towards improving interface modularity in legacy java software through automated refactoring
Upload: new-york-city-college-of-technology-computer-systems-technology-colloquium
Post on 23-Jan-2017
584 views
TRANSCRIPT
![Page 1: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/1.jpg)
Towards Improving InterfaceModularity in Legacy Java
Software through AutomatedRefactoring
Raffi Khatchadourian, Olivia MooreComputer Systems Technology, New York City College of Technology
City University of New York, USA
Hidehiko MasuharaMathematical and Computing Science, Tokyo Institute of Technology,
Japan
International Workshop on Language Modularity 2016 (LaMOD'16)International Conference on Modularity (MODULARITY'16)
Málaga, Spain
March 15, 2016
![Page 2: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/2.jpg)
Some History
Java was invented in the 90's as an Object-Oriented language.Largest change was in ~2005 with Java 5.
Generics.Enhanced for loops.Annotations.Type-safe enumerations.Concurrency enhancements (AtomicInteger).
![Page 3: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/3.jpg)
Java 8 is Massive
10 years later, Java 8 is packed with new features.
![Page 4: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/4.jpg)
Lambda Expressions
A block of code that you can pass around so it can beexecuted later, once or multiple times.
Anonymous methods.Reduce verbosity caused by anonymous classes.
![Page 5: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/5.jpg)
How are they different from Java methods?
![Page 6: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/6.jpg)
Lambdas(int x, int y) -> x + y
() -> 42
(String s) -> {System.out.println(s);}
() -> {return "Hello";}
![Page 7: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/7.jpg)
Using Lambdas In CollectionsJava 8 introduced a forEach() method for Collections that accepts a
lambda expression.
List<String> myList = Arrays.asList({"one", "two", "three"}); myList.forEach((String s) -> {System.out.println(s);); //prints each string in the list.
Or, more simply:
myList.forEach(s -> System.out.println(s)); //the type of s is inferred.
![Page 8: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/8.jpg)
Default MethodsAdd default behaviors to interfaces
![Page 9: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/9.jpg)
Why default methods?Java 8 has lambda expressions. We want to start using them:
List<?> list = ... list.forEach(...); // lambda code goes here
![Page 10: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/10.jpg)
There's a problemThe forEach method isn’t declared by java.util.List nor thejava.util.Collection interface because doing so would break
existing implementations.
![Page 11: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/11.jpg)
Default MethodsWe have lambdas, but we can't force new behaviors into current
libraries.
Solution: default methods.
![Page 12: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/12.jpg)
Default MethodsTraditionally, interfaces can't have method definitions (justdeclarations).Default methods supply default implementations of interfacemethods.By default, implementers will receive this implementation if they don'tprovide their own.
![Page 13: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/13.jpg)
Examples
![Page 14: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/14.jpg)
Example 1Basics
![Page 15: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/15.jpg)
public interface A {
default void foo() { System.out.println("Calling A.foo()"); } }
public class Clazz implements A { }
![Page 16: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/16.jpg)
Client code
Clazz clazz = new Clazz(); clazz.foo();
Output
"Calling A.foo()"
![Page 17: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/17.jpg)
Example 2Getting messy
![Page 18: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/18.jpg)
public interface A {
default void foo(){ System.out.println("Calling A.foo()"); } }
public interface B {
default void foo(){ System.out.println("Calling B.foo()"); }
}
public class Clazz implements A, B { }
Does this code compile?
![Page 19: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/19.jpg)
Of course not (Java is not C++)!
class Clazz inherits defaults for foo() from bothtypes A and B
How do we fix it?
![Page 20: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/20.jpg)
Option A:
public class Clazz implements A, B { public void foo(){/* ... */} }
We resolve it manually by overriding the conflicting method.
Option B:
public class Clazz implements A, B { public void foo(){ A.super.foo(); // or B.super.foo() } }
We call the default implementation of method foo() from eitherinterface A or B instead of implementing our own.
![Page 21: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/21.jpg)
Going back to the example of forEach method, how can we force it'sdefault implementation on all of the iterable collections?
![Page 22: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/22.jpg)
Let's take a look at the Java UML for all the iterable Collections:
To add a default behavior to all the iterable collections, a defaultforEach method was added to the Iterable<E> interface.
![Page 23: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/23.jpg)
We can find its default implementation in java.lang.Iterableinterface:
@FunctionalInterface public interface Iterable { Iterator iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }
![Page 24: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/24.jpg)
The forEach method takes a java.util.function.Consumerfunctional interface type as a parameter, which enables us to pass in a
lambda or a method reference as follows:
List<?> list = ... list.forEach(System.out::println);
This is also valid for Sets and Queues, for example, since both classesimplement the Iterable interface.Specific collections, e.g., UnmodifiableCollection, may overridethe default implementation.
![Page 25: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/25.jpg)
SummaryDefault methods can be seen as a bridge between lambdas and JDKlibraries.Can be used in interfaces to provide default implementations ofotherwise abstract methods.
Clients can optionally implement (override) them.Can eliminate the need for skeletal implementators like
.Can eliminate the need for utility classes like .
static methods are now also allowed in interfaces.
AbstractCollectionCollections
![Page 26: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/26.jpg)
Open ProblemsCan eliminate the need for skeletal implementators like
.AbstractCollection
![Page 27: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/27.jpg)
MotivationTwo cases:
1. Complete migration of skeletal implementation to interface.Makes type hierarchy less complicated.
One less type.Makes interfaces easier to implement.
No global analysis required to find skeletal implemention.Makes interfaces easier to maintain.
No simultaneous modifications between interface and skeletalimplementation required.
2. Partial migration of skeletal implementation to interface.Possibly makes interfaces easier to implement.
All implementations may not need to extend the skeletalimplementation.
Possibly makes interfaces easier to maintain.Possibily less simultaneous modifications between interface andskeletal implementation required.
![Page 28: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/28.jpg)
Open ProblemsCan eliminate the need for skeletal implementators like
.AbstractCollection
Can we automate this?1. How do we determine if an interface
implementor is "skeletal?"2. What is the criteria for an instance method to be
converted to a default method?3. What if there is a hierarchy of skeletal
implementors, e.g., AbstractCollection,AbstractList?
4. How do we preserve semantics?5. What client changes are necessary?
![Page 29: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/29.jpg)
Skeletal ImplementatorsAbstract classes that provide skeletal
implementations for interfaces.
Let's take a look at the Java UML for AbstractCollection:
![Page 30: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/30.jpg)
Why Is This Complicated?Corresponds to moving a skeletal implementation to an interface.
# From a class To an interface1. instance method default method
Can we not simply use a move method refactoring?
No. The inherent problem is that, unlike classes,interfaces may extend multiple interfaces. As such, wenow have a kind of multiple inheritance problem to
deal with.
![Page 31: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/31.jpg)
Some (perhaps) ObviousPreconditions
Source instance method must not access any instance fields.Interfaces may not have instance fields.
Can't currently have a default method in the target interface withthe same signature.Can't modify target method's visibility.
![Page 32: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/32.jpg)
Some Obvious TasksMust replace the target method in the interface (add a body to it).Must add the default keyword.Must remove any @Override annotations (it's top-level now).If nothing left in abstract class, remove it?Need to deal with documentation.
![Page 33: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/33.jpg)
Some Not-so-obviousPreconditions
Suppose we have the following situation:
interface I { void m(); }
interface J { void m(); }
abstract class A implements I, J { @Override void m() {...} }
Here, A provides a partial implementation of I.m(), which also happensto be declared as part of interface J.
![Page 34: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/34.jpg)
Some Not-so-obviousPreconditions
Now, we pull up A.m() to be a default method of I:
interface I { default void m() {..} //was void m(); }
interface J { void m(); //stays the same. }
abstract class A implements I, J { //now empty, was: void m() {...} }
We now have a compile-time error in A because A needs to declarewhich m() it inherits.In general, inheritance hierarchies may be large and complicated.Other preconditions may also exist (work in progress).
![Page 35: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/35.jpg)
Live DemoMigrate Skeletal Implementation to Interface prototype refactoring plug-in
for Eclipse
![Page 36: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/36.jpg)
References & Documentation &Interesting Links
Horstmann, Cay S. (2014-01-10). Java SE8 for the Really Impatient: A Short Course on theBasics (Java Series). Pearson Education.
http://download.java.net/jdk8/docs/http://download.java.net/jdk8/docs/api/https://blogs.oracle.com/thejavatutorials/entry/jdk_8_documentation_developer_previewhttp://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
![Page 37: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring](https://reader034.vdocument.in/reader034/viewer/2022042706/588592ee1a28ab84668b74af/html5/thumbnails/37.jpg)
Questions?