Top Banner
Towards Improving Interface Modularity in Legacy Java Software through Automated Refactoring Ra Khatchadourian, Olivia Moore Computer Systems Technology, New York City College of Technology City University of New York, USA Hidehiko Masuhara Mathematical and Computing Science, Tokyo Institute of Technology, Japan International Workshop on Language Modularity 2016 (LaMOD'16) at the International Conference on Modularity (MODULARITY'16) Málaga, Spain March 15, 2016
32

Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Apr 07, 2017

Download

Technology

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Towards Improving InterfaceModularity in Legacy Java

Software through AutomatedRefactoring

Ra� 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) atthe 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

New Features in Java 8

Largest change was in ~2005 with Java 5.10 years later, Java 8 is packed with new features.Java 9 is on the horizon (Project Jigsaw, i.e., "modular Java", etc.)Our focus is Java 8 enhanced interfaces that allow default methods.

Page 3: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Java InterfacesA list of public method declarations (no bodies) that

concrete implementers (classes) must de�ne.

Page 4: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

The Java Interface Type

Cannot be instantiated (abstract).Cannot contain instance �elds.Can extend other interfaces.Can contain public static �elds and methods (new in Java 8).

Multiple classes can implement an interface and aninterface can be implemented by multiple classes.

Page 5: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

ExampleList contains declarations of methods common to all lists.

interface List<E> { //... /** * Removes all of the elements from this list (optional operation). * @throws UnsupportedOperationException if the clear operation * is not supported by this list. */ void clear(); //... }

MyList is a particular kind of list.

class MyList<E> implements List<E> { //... @Override public void clear() { // not supported. throw new UnsupportedOperationException(); } //... }

A List can refer to MyList instances in clients.

List<E> list = new MyList<>();

Page 6: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

The Skeletal ImplementationPattern

Default behavior for interface methods.

Page 7: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

ProblemInterface implementers may share common functionality.Some interface methods may be optional (like List.clear()).

Page 8: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Skeletal ImplementationsProvide separate abstract class as a partial interface implementation[Bloch'08].Implementers extend the skeletal implementation instead.Inherit "default" and/or partial interface method de�ntions.Makes implementing the interface easier.

Page 9: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Exampleinterface List<E> { //... /** * Removes all of the elements from this list (optional operation). * @throws UnsupportedOperationException if the clear operation * is not supported by this list. */ void clear(); //... }

abstract class AbstractList<E> implements List<E> { //... @Override public void clear() { // not supported. throw new UnsupportedOperationException(); } //... }

class MyList<E> extends AbstractList<E> { //... // Inherits default implementation of clear(). }

Page 10: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

IssuesFlexibility

Java has single class inheritance -> classes cannot extend classesother than the skeletal implementation (can use delegation instead[Bloch'08]).

EvolvabilityInterface modi�cations must be in sync with skeletalimplementions in separate classes.

ModularityNo syntatical path from the interface to its skeletal implementation.Developers wishing to implement an interface may need a globalanalysis to �nd corresponding skeletal implementers.

Page 11: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Default MethodsAdd default behaviors to interfaces

Page 12: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Default MethodsTraditionally, interfaces can't have method de�nitions (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

Examples

Page 14: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Example 1Basics

Page 15: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

interface List<E> { //... default void clear() { throw new UnsupportedOperationException(); } } class MyList<E> implements List<E> { //... }

Page 16: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Client code

List<E> list = new MyList<>(); list.clear();

Result

An UnsupportedOperationException is thrown.

Page 17: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Example 2Getting messy

Page 18: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

interface List<E> { //... default void clear (){ throw new UnsupportedOperationException(); } } interface Queue<E> { default void clear() { System.err.println("Unsupported operation."); } }

class MyList<E> implements List<E>, Queue<E> { }

Does this code compile?

Page 19: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Of course not (Java is not C++)!

class MyList inherits defaults for clear() from bothtypes List and Queue

How do we �x it?

Page 20: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Option A:

class MyList<E> implements List<E>, Queue<E> { @Override public void clear() {/* ... */} }

We resolve it manually by overriding the con�icting method.

Option B:

class MyList<E> implements List<E>, Queue<E> { @Override public void clear (){ List.super.clear(); // or Queue.super.clear() } }

We call the default implementation of method clear() from eitherinterface List or Queue instead of implementing our own.

Page 21: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Work in ProgressCan eliminate the need for skeletal implementations?

Page 22: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

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 �nd skeletal implemention.Makes interfaces easier to maintain.

No simultaneous modi�cations 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 modi�cations between interface andskeletal implementation required.

Page 23: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Work in ProgressCan eliminate the need for skeletal implementations?

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 24: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Skeletal ImplementatorsAbstract classes that provide skeletal

implementations for interfaces.

Let's take a look at the Java UML for : AbstractCollection

Page 25: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Why is this Complicated?Corresponds to converting and migrating a skeletal (instance) method

implementation to an interface.

From a class To an interfaceinstance method default method

Can we not simply use a "Pull Up Method" [Fowler'99] refactoring?

Not exactly. The inherent problem is that, unlikeclasses, interfaces may extend multiple interfaces. As

such, we now have a kind of multiple inheritanceproblem to deal with.

Page 26: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Some (perhaps) ObviousPreconditions

Source instance method must not access any instance �elds.Interfaces may not have instance �elds.

Can't currently have a default method in the target interface withthe same signature.Can't modify target method's visibility.

Page 27: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

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 28: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

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 29: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Some Not-so-obviousPreconditions

Now, we convert and migrate A.m() to 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 30: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

More InformationProject Website

http://openlab.citytech.cuny.edu/interfacerefactoring

Prototype ImplementationEclipse Plug-in; in progress

http://github.com/khatchad/Java-8-Interface-Refactoring

Page 31: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Time for a Live Demo?Migrate Skeletal Implementation to Interface prototype refactoring plug-in

for Eclipse

Page 32: Towards Improving Interface Modularity in Legacy Java Software Through Automated Refactoring

Questions?