Defaultification Refactoring: A Tool for
Automatically Converting Java Methods to Default
Raffi Khatchadourian1
Hidehiko Masuhara2
1
CUNY Hunter College & the Graduate Center, 2
Tokyo Institute of Technology
Introduction
Java 8 enhanced interfaces enable developers to write default (instance)
methods that include an implementation that implementers will inherit
if one is not provided [13]. Advantages in migrating legacy code from
using the skeletal implementation pattern to default methods include
foregoing the need for subclassing, having classes inherit behavior (but
not state) from multiple interfaces [4], and facilitating local reason-
ing [9]. We demonstrate our tool Migrate Skeletal Implemen-
tation to Interface for transforming legacy Java code to use de-
fault methods.
The related Pull Up Method refactoring tool [3,14] manipulates
a type hierarchy by safely moving methods from a subclass up into a
super class so that all subclasses may inherit from it. This refactoring is
fundamentally different from migrating method definitions from skeletal
implementations to interfaces as default methods.
Our refactoring tool (available at http://git.io/v2nX0) is imple-
mented as an open source Eclipse (http://eclipse.org) plug-in built
atop of the Java Development Tools (JDT) (http://eclipse.org/jdt)
refactoring infrastructure [2]. For the tool evaluation, an extensive
refactoring test suite was created, featuring 259 refactoring regression
tests, triggered via continuous integration. The usefulness of the tool
was assess via the analysis of 19 Java projects of varying size and do-
main with a total of ∼2.7 million lines of code. Additionally, pull requests
(patches) of the refactoring results were submitted to popular GitHub
(http://github.com) repositories as a preliminary study.
The details of the underlying approach, as well as thorough experimen-
tal results, can be found in our previous work [8]. Beyond [8], we make
the following specific contributions:
Implementation details A thorough treatment of the novel aspects of
the tool implementation is presented in detail.
User perspective A broad overview of how our tool is used to perform
large-scale refactorings is given.
Envisioned Users
The users we envision our tool attracting are those who are tasked with
maintaining and/or improving legacy (currently) Java systems. Devel-
opers with even little refactoring experience may use our tool.
Software Engineering Challenges
Background and Motivation
Figure 1: Screenshot of the refactoring preview pane.
Fig. 1 portrays a screenshot of the refactoring preview pane that a user
is presented with prior to executing the refactoring on a simplified ex-
ample. Fig. 1 consists of two panes, namely, the “Original Source” and
the “Refactored Source,” with the former being in input to the tool and
the latter the proposed output.
Although useful, there are several drawbacks to the skeletal implemen-
tation pattern, especially w.r.t. inheritance, modularity, and bloat [8].
Many of the problems can be solved with default methods that are part
of the enhanced interface feature of Java 8 [5, Ch. 9]. With default
methods, implementers of I can simultaneously benefit from the default
implementation of m() and extend a different class.
Although Fig. 1 portrays a scenario where the refactoring succeeds,
cases exist where executing the refactoring would produce either type-
incorrect or semantically-inequivalent results. For example, consider the
following:
interface I {void m();}
interface J {default void m() {/* ... */}}
abstract class C implements I,J {void m() {/*...*/}}
Here, migrating method C.m() to interface I as a default method would
cause a compilation error due to class C now inheriting ambiguous
method definitions of method m(). Also, default methods have many
advantageous over the skeletal implementation pattern, however, there
are some potential trade-offs.
Implementation Challenges
Implementation-specific challenges include:
Architecture What is the best way to organize such a refactoring tool?
Reuse Given that the refactoring problem shares similarity with the
Pull Up Method refactoring, how can we best leverage
existing code from that plug-in here?
Applicability Do the various assumptions made in the approach scale
to real-world software refactoring?
Validation Given the significant number of “corner-cases” involved in
this refactoring, how can we ensure to developers that the
resulting refactoring code will be type-correct and
semantically equivalent to the original?
Usability Challenges
There are also challenges specific to developer adoption. Large scale
and broad changes may not be immediately appealing to developers of
mature and highly utilized projects due to risk.
Implementation
The Migrate Skeletal Implementation to Interface refac-
toring is implemented as an open source plug-in for the Eclipse IDE
(available at http://git.io/v2nX0).
Workflow
Figure 2: High-level system workflow.
Fig. 2 depicts the high-level workflow. The developer is presented with
options regarding the invasiveness of the refactoring (step 2). The bulk
of the computationally intensive precondition checking occurs in step
4.
Figure 3: Architecture and plug-in dependency diagram.
Architecture and Dependencies
Fig. 3 portrays the overall plug-in architecture and dependency overview
of our refactoring tool. The foundational Eclipse plug-ins and their de-
pendencies are also depicted in Fig. 3.
Relationship to Other Refactoring Plug-ins
The plug-in menu options are coupled with other Eclipse reorganization
refactorings. Some of our implementation leverages and adapts code
from the Eclipse Pull Up Method refactoring, especially those re-
lated to determining if a code entity is accessible from another type.
Technical Details
We make extensive use of ITypeHierarchy to traverse the input meth-
ods’ relationships to other types in the project. To demonstrate the
imperative-style code that realizes the more declarative-style type con-
straints, consider the constraint for method invocation. This constraint
applies to any program construct in the form of E.m(E1, . . . , En) to
a virtual method M where E is an expression. We must ensure that
there is a corresponding method in the type hierarchy of the destination
interface when E = this as the type of this will change.
We use ITypeHierarchy to check that the called method exists in
the destination interface’s “super type” hierarchy via a call to
IType.newSupertypeHierarchy(). The checking is achieved via the following:
mInHier = isInHier(calledMeth, destInterSuperHier);
boolean isMethInHier(IMethod m, ITypeHierarchy h) {
return Stream.of(h.getAllTypes()).anyMatch(t -> {
IMethod[] meths = t.findMethods(m);
return meth != null && meths.length > 0;});}
Real-world Applicability
To make our approach applicable to real-world scenarios, e.g., if an input
method’s destination interface is outside of the considered source code,
it is conservatively labeled as non-migratable (i.e., failed precondition).
Usability and Managing Risk
We allow developers to choose whether empty skeletal implementation
classes should be removed. We additionally require no mismatches in-
volving exception throws clauses and return types between source and
target methods. Lastly, an option to not consider non-standard (out-
side java.lang) annotation differences is available, which may be useful in
projects not using such processing frameworks. Developers have sev-
eral other options, including whether to include only abstract classes
as input, increasing the likelihood classes that truly are skeletal imple-
menters.
Evaluation
Our tool successfully converted ∼20% of methods possibly participating
in the skeletal implementation pattern to interfaces as default meth-
ods [8] in 19 real-world, open source projects of varying size and domain
with a total of ∼2.7 million lines of code. The correctness of the refac-
toring approach was validated by ensuring that no compilation errors
existed before and after the refactoring. Furthermore, we verified that
all unit tests results were identical before and after the refactoring. A
preliminary pull request study was also performed to ensure that the
musically produced results matched what experienced developers may
have written. Four projects accepted our pull requests, and the tool’s
results were integrated into the projects.
To validate our implementation, our plug-in features an extensive refac-
toring test suite with over 200 tests. The significant number of test
cases exercises many corner-cases that appear in the refactoring.
Related Work
Current Eclipse refactorings do not have the capability to deal with de-
fault method conversions. An important difference between our tool
and Pull Up Method is related to a “stubbing” behavior. For ex-
ample, in Pull Up Method, if an instance method call in the source
method exists, that method may be available in the target type. If it
is not, an abstract method (stub) can be created in the target type
to compensate. However, in our case, there may be no relationship
between the called instance method and the destination interface.
Others [1,12,14] reorganize type hierarchies, but not for default meth-
ods. [6,7] transform Java programs to use lambda expressions and enu-
merated types, respectively, while [11] demacrofies C++11 programs.
Conclusion & Future Work
A refactoring tool that incorporates an efficient, fully-automated,
type constraint-based, semantics-preserving approach that migrates the
skeletal implementation pattern in legacy Java code to instead use de-
fault methods has been demonstrated. The tool is implemented as an
Eclipse IDE plug-in and was evaluated using several techniques.
In the future, we plan to compensate for situations where source meth-
ods directly accessing fields or methods outside destination interfaces.
We also plan to improve refactoring speed [10].
References
[1] Zakarea Alshara, Abdelhak-Djamel Seriai, Chouki Tibermacine, Hinde Lilia Bouziane,
Christophe Dony, and Anas Shatnawi. Migrating large object-oriented applications into
component-based ones: Instantiation and inheritance transformation. In International Con-
ference on Generative Programming: Concepts & Experience, 2015.
[2] Dirk Bäumer, Erich Gamma, and Adam Kiezun. Integrating refactoring support into a Java
development tool. In ACM SIGPLAN conference on Object-Oriented Programming, Systems,
Languages, and Applications, 2001.
[3] Martin Fowler. Refactoring: Improving the Design of Existing Code. Addison-Wesley Profes-
sional, 1999.
[4] Brian Goetz. Interface evolution via virtual extensions methods. Technical report, Oracle
Corporation, June 2011.
[5] James Gosling, Bill Joy, Guy L. Steele, Gilad Bracha, and Alex Buckley. The Java Language
Specification. Addison-Wesley Professional, 2014.
[6] Alex Gyori, Lyle Franklin, Danny Dig, and Jan Lahoda. Crossing the gap from imperative to
functional programming through refactoring. In ACM SIGSOFT International Symposium on
the Foundations of Software Engineering, 2013.
[7] Raffi Khatchadourian. Automated refactoring of legacy Java software to enumerated types.
Automated Software Engineering, 24(4):757–787, December 2017.
[8] Raffi Khatchadourian and Hidehiko Masuhara. Automated refactoring of legacy Java software
to default methods. In International Conference on Software Engineering, 2017.
[9] Raffi Khatchadourian, Olivia Moore, and Hidehiko Masuhara. Towards improving interface
modularity in legacy java software through automated refactoring. In International Conference
on Modularity Companion, 2016.
[10] Jongwook Kim, Don Batory, Danny Dig, and Maider Azanza. Improving refactoring speed by
10x. In International Conference on Software Engineering, 2016.
[11] Aditya Kumar, Andrew Sutton, and Bjarne Stroustrup. Rejuvenating C++ programs through
demacrofication. In International Conference on Software Maintenance, 2012.
[12] Ivan Moore. Automatic inheritance hierarchy restructuring and method refactoring. In ACM
SIGPLAN conference on Object-Oriented Programming, Systems, Languages, and Applications,
1996.
[13] Oracle Corporation. Java Programming Language Enhancements.
[14] Frank Tip, Robert M. Fuhrer, Adam Kieżun, Michael D. Ernst, Ittai Balaban, and Bjorn De Sut-
ter. Refactoring using type constraints. ACM Transactions on Programming Languages and
Systems, 2011.
International Conference on Automated Software Engineering, Oct 30–Nov 3, 2017, Urbana-Champaign, Illinois, USA

Defaultification Refactoring: A Tool for Automatically Converting Java Methods to Default

  • 1.
    Defaultification Refactoring: ATool for Automatically Converting Java Methods to Default Raffi Khatchadourian1 Hidehiko Masuhara2 1 CUNY Hunter College & the Graduate Center, 2 Tokyo Institute of Technology Introduction Java 8 enhanced interfaces enable developers to write default (instance) methods that include an implementation that implementers will inherit if one is not provided [13]. Advantages in migrating legacy code from using the skeletal implementation pattern to default methods include foregoing the need for subclassing, having classes inherit behavior (but not state) from multiple interfaces [4], and facilitating local reason- ing [9]. We demonstrate our tool Migrate Skeletal Implemen- tation to Interface for transforming legacy Java code to use de- fault methods. The related Pull Up Method refactoring tool [3,14] manipulates a type hierarchy by safely moving methods from a subclass up into a super class so that all subclasses may inherit from it. This refactoring is fundamentally different from migrating method definitions from skeletal implementations to interfaces as default methods. Our refactoring tool (available at http://git.io/v2nX0) is imple- mented as an open source Eclipse (http://eclipse.org) plug-in built atop of the Java Development Tools (JDT) (http://eclipse.org/jdt) refactoring infrastructure [2]. For the tool evaluation, an extensive refactoring test suite was created, featuring 259 refactoring regression tests, triggered via continuous integration. The usefulness of the tool was assess via the analysis of 19 Java projects of varying size and do- main with a total of ∼2.7 million lines of code. Additionally, pull requests (patches) of the refactoring results were submitted to popular GitHub (http://github.com) repositories as a preliminary study. The details of the underlying approach, as well as thorough experimen- tal results, can be found in our previous work [8]. Beyond [8], we make the following specific contributions: Implementation details A thorough treatment of the novel aspects of the tool implementation is presented in detail. User perspective A broad overview of how our tool is used to perform large-scale refactorings is given. Envisioned Users The users we envision our tool attracting are those who are tasked with maintaining and/or improving legacy (currently) Java systems. Devel- opers with even little refactoring experience may use our tool. Software Engineering Challenges Background and Motivation Figure 1: Screenshot of the refactoring preview pane. Fig. 1 portrays a screenshot of the refactoring preview pane that a user is presented with prior to executing the refactoring on a simplified ex- ample. Fig. 1 consists of two panes, namely, the “Original Source” and the “Refactored Source,” with the former being in input to the tool and the latter the proposed output. Although useful, there are several drawbacks to the skeletal implemen- tation pattern, especially w.r.t. inheritance, modularity, and bloat [8]. Many of the problems can be solved with default methods that are part of the enhanced interface feature of Java 8 [5, Ch. 9]. With default methods, implementers of I can simultaneously benefit from the default implementation of m() and extend a different class. Although Fig. 1 portrays a scenario where the refactoring succeeds, cases exist where executing the refactoring would produce either type- incorrect or semantically-inequivalent results. For example, consider the following: interface I {void m();} interface J {default void m() {/* ... */}} abstract class C implements I,J {void m() {/*...*/}} Here, migrating method C.m() to interface I as a default method would cause a compilation error due to class C now inheriting ambiguous method definitions of method m(). Also, default methods have many advantageous over the skeletal implementation pattern, however, there are some potential trade-offs. Implementation Challenges Implementation-specific challenges include: Architecture What is the best way to organize such a refactoring tool? Reuse Given that the refactoring problem shares similarity with the Pull Up Method refactoring, how can we best leverage existing code from that plug-in here? Applicability Do the various assumptions made in the approach scale to real-world software refactoring? Validation Given the significant number of “corner-cases” involved in this refactoring, how can we ensure to developers that the resulting refactoring code will be type-correct and semantically equivalent to the original? Usability Challenges There are also challenges specific to developer adoption. Large scale and broad changes may not be immediately appealing to developers of mature and highly utilized projects due to risk. Implementation The Migrate Skeletal Implementation to Interface refac- toring is implemented as an open source plug-in for the Eclipse IDE (available at http://git.io/v2nX0). Workflow Figure 2: High-level system workflow. Fig. 2 depicts the high-level workflow. The developer is presented with options regarding the invasiveness of the refactoring (step 2). The bulk of the computationally intensive precondition checking occurs in step 4. Figure 3: Architecture and plug-in dependency diagram. Architecture and Dependencies Fig. 3 portrays the overall plug-in architecture and dependency overview of our refactoring tool. The foundational Eclipse plug-ins and their de- pendencies are also depicted in Fig. 3. Relationship to Other Refactoring Plug-ins The plug-in menu options are coupled with other Eclipse reorganization refactorings. Some of our implementation leverages and adapts code from the Eclipse Pull Up Method refactoring, especially those re- lated to determining if a code entity is accessible from another type. Technical Details We make extensive use of ITypeHierarchy to traverse the input meth- ods’ relationships to other types in the project. To demonstrate the imperative-style code that realizes the more declarative-style type con- straints, consider the constraint for method invocation. This constraint applies to any program construct in the form of E.m(E1, . . . , En) to a virtual method M where E is an expression. We must ensure that there is a corresponding method in the type hierarchy of the destination interface when E = this as the type of this will change. We use ITypeHierarchy to check that the called method exists in the destination interface’s “super type” hierarchy via a call to IType.newSupertypeHierarchy(). The checking is achieved via the following: mInHier = isInHier(calledMeth, destInterSuperHier); boolean isMethInHier(IMethod m, ITypeHierarchy h) { return Stream.of(h.getAllTypes()).anyMatch(t -> { IMethod[] meths = t.findMethods(m); return meth != null && meths.length > 0;});} Real-world Applicability To make our approach applicable to real-world scenarios, e.g., if an input method’s destination interface is outside of the considered source code, it is conservatively labeled as non-migratable (i.e., failed precondition). Usability and Managing Risk We allow developers to choose whether empty skeletal implementation classes should be removed. We additionally require no mismatches in- volving exception throws clauses and return types between source and target methods. Lastly, an option to not consider non-standard (out- side java.lang) annotation differences is available, which may be useful in projects not using such processing frameworks. Developers have sev- eral other options, including whether to include only abstract classes as input, increasing the likelihood classes that truly are skeletal imple- menters. Evaluation Our tool successfully converted ∼20% of methods possibly participating in the skeletal implementation pattern to interfaces as default meth- ods [8] in 19 real-world, open source projects of varying size and domain with a total of ∼2.7 million lines of code. The correctness of the refac- toring approach was validated by ensuring that no compilation errors existed before and after the refactoring. Furthermore, we verified that all unit tests results were identical before and after the refactoring. A preliminary pull request study was also performed to ensure that the musically produced results matched what experienced developers may have written. Four projects accepted our pull requests, and the tool’s results were integrated into the projects. To validate our implementation, our plug-in features an extensive refac- toring test suite with over 200 tests. The significant number of test cases exercises many corner-cases that appear in the refactoring. Related Work Current Eclipse refactorings do not have the capability to deal with de- fault method conversions. An important difference between our tool and Pull Up Method is related to a “stubbing” behavior. For ex- ample, in Pull Up Method, if an instance method call in the source method exists, that method may be available in the target type. If it is not, an abstract method (stub) can be created in the target type to compensate. However, in our case, there may be no relationship between the called instance method and the destination interface. Others [1,12,14] reorganize type hierarchies, but not for default meth- ods. [6,7] transform Java programs to use lambda expressions and enu- merated types, respectively, while [11] demacrofies C++11 programs. Conclusion & Future Work A refactoring tool that incorporates an efficient, fully-automated, type constraint-based, semantics-preserving approach that migrates the skeletal implementation pattern in legacy Java code to instead use de- fault methods has been demonstrated. The tool is implemented as an Eclipse IDE plug-in and was evaluated using several techniques. In the future, we plan to compensate for situations where source meth- ods directly accessing fields or methods outside destination interfaces. We also plan to improve refactoring speed [10]. References [1] Zakarea Alshara, Abdelhak-Djamel Seriai, Chouki Tibermacine, Hinde Lilia Bouziane, Christophe Dony, and Anas Shatnawi. Migrating large object-oriented applications into component-based ones: Instantiation and inheritance transformation. In International Con- ference on Generative Programming: Concepts & Experience, 2015. [2] Dirk Bäumer, Erich Gamma, and Adam Kiezun. Integrating refactoring support into a Java development tool. In ACM SIGPLAN conference on Object-Oriented Programming, Systems, Languages, and Applications, 2001. [3] Martin Fowler. Refactoring: Improving the Design of Existing Code. Addison-Wesley Profes- sional, 1999. [4] Brian Goetz. Interface evolution via virtual extensions methods. Technical report, Oracle Corporation, June 2011. [5] James Gosling, Bill Joy, Guy L. Steele, Gilad Bracha, and Alex Buckley. The Java Language Specification. Addison-Wesley Professional, 2014. [6] Alex Gyori, Lyle Franklin, Danny Dig, and Jan Lahoda. Crossing the gap from imperative to functional programming through refactoring. In ACM SIGSOFT International Symposium on the Foundations of Software Engineering, 2013. [7] Raffi Khatchadourian. Automated refactoring of legacy Java software to enumerated types. Automated Software Engineering, 24(4):757–787, December 2017. [8] Raffi Khatchadourian and Hidehiko Masuhara. Automated refactoring of legacy Java software to default methods. In International Conference on Software Engineering, 2017. [9] Raffi Khatchadourian, Olivia Moore, and Hidehiko Masuhara. Towards improving interface modularity in legacy java software through automated refactoring. In International Conference on Modularity Companion, 2016. [10] Jongwook Kim, Don Batory, Danny Dig, and Maider Azanza. Improving refactoring speed by 10x. In International Conference on Software Engineering, 2016. [11] Aditya Kumar, Andrew Sutton, and Bjarne Stroustrup. Rejuvenating C++ programs through demacrofication. In International Conference on Software Maintenance, 2012. [12] Ivan Moore. Automatic inheritance hierarchy restructuring and method refactoring. In ACM SIGPLAN conference on Object-Oriented Programming, Systems, Languages, and Applications, 1996. [13] Oracle Corporation. Java Programming Language Enhancements. [14] Frank Tip, Robert M. Fuhrer, Adam Kieżun, Michael D. Ernst, Ittai Balaban, and Bjorn De Sut- ter. Refactoring using type constraints. ACM Transactions on Programming Languages and Systems, 2011. International Conference on Automated Software Engineering, Oct 30–Nov 3, 2017, Urbana-Champaign, Illinois, USA