Bean generation
Stop writing getters and setters
Stephen Colebourne, @jodastephen
Engineering Lead, OpenGamma
September 2016
http://blog.joda.org
Stephen Colebourne
● Java Champion, regular conference speaker
● Best known for date & time - Joda-Time and JSR-310
● More Joda projects - http://www.joda.org
● Major contributions in Apache Commons
● Blog - http://blog.joda.org
● Worked at OpenGamma for 6 years
Strata, from OpenGamma
● Open Source market risk library
● Valuation and risk calcs for finance
○ interest rate swap, FRA, CDS
● Great example of Java SE 8 coding style
http://strata.opengamma.io/
Introduction
⇒
Why use beans?
● Beans are used in most applications
● Common denominator between applications & libraries
● ORMs (Hibernate, JPA, etc.)
● Serialization (Binary, JSON, XML, etc.)
● Mappers/configuration (Spring, Dozer, etc.)
What is a bean?
● JavaBean specification v1.01, from 1997
● Focus on software components, COM/DCOM
● Manipulated visually in GUIs
● Java components within MS Word/Excel !!!
● References to floppy disks !!!
What is a bean?
● JavaBeans must extend java.awt.Component
● Created via standard factories
● No use of casts of instanceof checks
● Checked exceptions, not unchecked
● Communication via events
● Very specific rules around capitalization
● Use of BeanInfo and PropertyEditor
What is a bean?
"Bean" != JavaBean
What is a mutable bean?
● Each tool has subtly different definition
● Most agree on
○ no-args constructor
○ getters match getXxx()
○ setters match setXxx()
○ equals() / hashCode() / toString()
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for mutable bean
/** Represents a person. */
public class Person {
/** The forename of the person. */
private String forename;
/** The surname of the person. */
private String surname;
/** The birth date of the person. */
private LocalDate birthDate;
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for mutable bean
/** Creates an empty instance of Person. */
public Person() {}
/** Gets the forename of the person. */
public String getForename() { … }
/** Sets the forename of the person. */
public void setForename(String forename) { … }
// same for surname/birthDate
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for mutable bean
/** Compares this person to another. */
public boolean equals(Object obj) { … }
/** Returns a suitable hash code. */
public int hashCode() { … }
/** Returns a string summary of this object. */
public String toString() { … }
What is an immutable bean?
● "Beans" has traditionally implied mutability
● Many tools can't handle immutable beans
● No setters, may have "withers"
● Class must be final, with final fields
● Factory or builder instead of constructor
Why immutable?
● Thread-safe
● Java Memory Model guarantees
● No need to trust other methods not to modify
● State checked and valid on construction
● Nulls can be eliminated
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for immutable bean
/** Represents a person. */
public final class Person {
/** The forename of the person. */
private final String forename;
/** The surname of the person. */
private final String surname;
/** The birth date of the person. */
private final LocalDate birthDate;
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for immutable bean
/** Obtains an instance of Person. */
public Person of(
String surname, String forename, LocalDate date) { … }
/** Gets the forename of the person. */
public String getForename() { … }
/** Returns a copy with the specified forename. */
public Person withForename(String forename) { … }
// same for surname/birthDate
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Pattern for immutable bean
/** Compares this person to another. */
public boolean equals(Object obj) { … }
/** Returns a suitable hash code. */
public int hashCode() { … }
/** Returns a string summary of this object. */
public String toString() { … }
Pattern for immutable bean
● May prefer to have a builder instead of a factory
// factory
Person person = Person.of("Stephen", "Colebourne", date);
// or builder
Person person = Person.builder()
.forename("Stephen")
.surname("Colebourne")
.birthDate(date)
.build();
What is a VALJO?
● POJO - Plain Old Java Object
● VALJO - Value Java Object
○ http://blog.joda.org/2014/03/valjos-value-java-objects.html
● No use of identity - equal is interchangeable
● Immutable bean with extra restrictions
○ may be suitable for conversion to value types in Java 10/11
○ logical state clearly defined and used in equals()/hashCode()
○ comparable consistent with equals()
○ constructor must be private
○ formal string representation that can be parsed
Creating beans
How to create beans
● Lots of different ways to create beans
● Best option depends on use case
● Mutable vs Immutable
Option 1 - Manual
● Write each bean manually
● Deathly boring
● Double deathly boring for immutable beans
● Error-prone
● Probably not tested or code reviewed
Option 2 - Another JVM language
● Kotlin code much shorter
// Kotlin immutable bean
data class Person(
val forename: String,
val surname: String,
val birthDate: LocalDate)
Option 2 - Another JVM language
● Groovy code much shorter
// Groovy mutable bean
class Customer {
String forename
String surname
LocalDate birthDate
Option 3 - Language change
● New language feature in Java
● Perhaps like Kotlin/Groovy
● Doesn't help us now
● Likely to be restrictive
Option 4 - IDE generation
● Eclipse / IntelliJ / NetBeans can generate the code
○ Eclipse uses Ctrl+Alt+S followed by R / O / H / S
○ IntelliJ uses Alt+Insert
● One time generation, doesn't handle change
● Can you express field is not null?
● Can you generate immutable builders?
● Still not tested or code reviewed
Option 5 - Use a tool
● AutoValue
● Immutables
● Lombok
● Joda-Beans
● (VALJOGen)
● (POJOmatic)
AutoValue
AutoValue
● Annotation processor
● Open Source, from Google
○ https://github.com/google/auto/tree/master/value
Annotation processing
● Additional step during compilation
● Compiler calls annotation processor
● Processor generates additional files
● If generated file is a .java file then it is compiled
Annotation processing
Person
(abstract)
PersonImpl
(concrete)
Compilation finds
annotations and
code generates
You write
abstract class
Annotation processing
● Maven
○ just add the dependency
● Eclipse with Maven
○ install m2e-apt plugin
○ turn it on in the preferences
● IntelliJ with Maven
○ turn it on in the preferences
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
AutoValue: your code
@AutoValue
public abstract class Person {
public static Person of(String name, LocalDate date) {
return new AutoValue_Person(name, date);
}
public abstract String getName();
public abstract LocalDate getBirthDate();
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
AutoValue: generated
@Generated("com.google.auto.value.processor.AutoValueProcessor")
final class AutoValue_Person extends Person {
private final String name;
private final LocalDate birthDate;
// constructor, getters, equals, hashCode, toString
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
AutoValue builder: your code
@AutoValue
public abstract class Person {
public static Builder builder() {
return new AutoValue_Person.Builder();
}
@AutoValue.Builder
public static abstract class Builder {
public abstract Builder name(String name);
public abstract Builder birthDate(LocalDate date);
public abstract Person build();
}
public abstract Builder toBuilder();
AutoValue options
● Handles name() or getName() convention
● Can override (underride) equals/hashCode/toString
● Can add any other method
● Can change fields to nullable using @Nullable
● Supports memoized fields
● Builder can have sub-builders for collections
● Pattern to handle builder validation
● Extensions API, but undocumented
AutoValue pros/cons
● Callers use Person like a normal bean
○ but they can see class is abstract
● Generated code is package scoped
○ you must write outline builder and/or static factory method
○ quite a lot of code still to write
● Simple, does sensible thing for most use cases
○ not that many options
● Only for immutable beans
Immutables
Immutables
● Annotation processor
● Open Source
○ https://immutables.github.io/
● Reacts to use Guava if available
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Immutables: your code
@Value.Immutable
public interface Person {
String getName();
LocalDate getBirthDate();
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Immutables: generated
@SuppressWarnings("all")
@Generated({"Immutables.generator", "ImmutablePerson"})
public final class ImmutablePerson implements Person {
private final String name;
private final LocalDate birthDate;
private ImmutablePerson(String name, LocalDate birthDate) {
this.name = name;
this.birthDate = birthDate;
}
// getters, withers, equals, hashCode, toString, builder
Immutables options
● Can generate from abstract class or interface
● Handles name() or getName() convention
● Can override (underride) equals/hashCode/toString
● Can add any other method
● Pre-computed hash code
● Instance interning
● and lots more!
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Immutables: hide implementation
@Value.Immutable
@Value.Style(visibility = PACKAGE)
public abstract class Person extends WithPerson {
public String getName();
public LocalDate getBirthDate();
public static class Builder
implements ImmutablePerson.Builder {}
}
Immutables pros/cons
● Many options and ways to generate
○ takes time to choose best option
● Callers see and use generated class (by default)
○ hiding generated class possible if you write more code
● Mutable beans supported
○ more like builders, do not follow JavaBeans spec
Lombok
Lombok
● Internal APIs
● Open Source
○ https://projectlombok.org/
● Uses agents and annotation processors
● Works best with Eclipse, but requires installing
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Lombok: your code - mutable
@Data
public class Person {
private String name;
private LocalDate birthDate;
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Lombok: generated- mutable
@Data
public class Person {
private String name;
private LocalDate birthDate;
// constructor, getters, setters, equals, hashCode, toString
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Lombok: your code - immutable
@Value
public class Person {
private String name;
private LocalDate birthDate;
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Lombok: generated - immutable
@Value
public final class Person {
private final String name;
private final LocalDate birthDate;
// constructor, getters, equals, hashCode, toString, builder
}
Lombok options
● Over 15 annotations and tweaks
● Use other annotations for more control
● Can add any other method
Lombok pros/cons
● No second class, proper immutable bean
○ resulting bean is exactly the same as manually written
● Works best with Maven and Eclipse
○ installation in Eclipse not via a standard plugin
● Uses internal API hackery
○ higher risk option
● Generated code is invisible
○ cannot step in when debugging
○ can "delombok" to code generated code
Joda-Beans
Joda-Beans
● Same-file regenerator
● Open Source, by me @jodastephen
○ http://www.joda.org/joda-beans/
● Adds autogenerated block to your code
● Generation using Maven/Gradle, on-save in Eclipse
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Joda-Beans: your code - mutable
@BeanDefinition
public class Person implements Bean {
@PropertyDefinition
private String name;
@PropertyDefinition
private LocalDate birthDate;
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Joda-Beans: generated - mutable
@BeanDefinition
public class Person implements Bean {
@PropertyDefinition
private String name;
@PropertyDefinition
private LocalDate birthDate;
// ---- AUTOGENERATED START ----
// getters, setters, equals, hashCode, toString, properties
// ----- AUTOGENERATED END -----
}
Properties
● C# and most other languages have properties
● Higher level than a field
● Bean is a set of properties
● Can list, get and set properties
○ like reflection
● Very useful abstraction for frameworks
Joda-Beans properties
● Bean provides abstraction for properties
● MetaBean acts like Class
● Can loop over MetaProperty for each property
○ meta bean acts as a hash-map of property name to property
○ no reflection
● BeanBuilder allows a bean to be created
○ this allows immutable beans to be created one property at a time
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Joda-Beans: your code immutable
@BeanDefinition
public class Person implements ImmutableBean {
@PropertyDefinition(validate = "notNull")
private String name;
@PropertyDefinition(validate = "notNull")
private LocalDate birthDate;
}
// Java 7
List<Person> people = loadPeople();
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Joda-Beans: generated immutable
@BeanDefinition
public class Person implements ImmutableBean {
@PropertyDefinition(validate = "notNull")
private String name;
@PropertyDefinition(validate = "notNull")
private LocalDate birthDate;
// ---- AUTOGENERATED START ----
// getters, equals, hashCode, toString, properties, builder
// ----- AUTOGENERATED END -----
}
Joda-Beans options
● Annotations allow field-level and bean-level control
● Control scope/style for getters/setters
● Supports pragmatic optional usage
● Can add any validation code
● Defaults/cross-validation for immutable bean builders
● Can default one property from another in builder
● Can fully override constructor
Joda-Beans pros/cons
● No second class, proper immutable bean
○ resulting bean is same as manually written
● Adds abstraction for properties without reflection
○ key reason to use Joda-Beans, but requires runtime dependency
● Built in XML, JSON, Binary serialization
● Generated code is visible for debugging
○ more code to checkin, but easy to ignore in review
○ proper Javadoc
● Plugin for Maven, Gradle and Eclipse with M2E
○ anyone want to volunteer to write an IntelliJ one?
Comparisons
Comparisons
● Annotation processor
○ AutoValue
○ Immutables
● Internal APIs
○ Lombok
● Same file regenerator
○ Joda-Beans
Comparisons
● All can generate a lot of useful code
○ getters, factories, builders, equals, hashCode, toString
● Some can generate mutable beans
● Only Joda-Beans generates C# style properties
● Each project has a different trade-off
Same class vs Generated class
● Same class (Joda-Beans, Lombok)
○ your code involves writing fields
○ caller sees concrete class
○ properly immutable
● Generated class (AutoValue, Immutables)
○ your code involves writing methods (more code)
○ caller sees abstract class or interface
○ is it really immutable?
○ IDE rename class typically breaks code
Collections
● Immutable beans should use Guava ImmutableList
● Builder needs to take List and convert internally
● All except Lombok do this correctly
Installation requirements
● AutoValue & Immutables use annotation processor
○ must be configured in IDE, extra plugin for Eclipse
● Lombok uses internal API hackery
○ requires specific Eclipse installation
● Joda-Beans runs as separate code regenerator
○ for Eclipse, just needs standard M2E
AutoValue vs Immutables
● AutoValue
○ you write abstract class
○ generated class is package-scoped
○ cannot generate static factory
○ must write builder outline manually
● Immutables
○ you write interface or abstract class
○ generated class is public (can be made private or package-scoped)
○ static factory and builder in generated class
○ lots of flexibility
Valid on checkout
● AutoValue, Immutables, Lombok
○ code invalid in IDE on checkout unless configured
○ only your code checked in
● Joda-Beans
○ code valid in IDE on checkout, even if not configured
○ your code and generated code checked in
Evaluate yourself
● GitHub project with everything setup for comparison
○ https://github.com/jodastephen/compare-beangen
● Includes 4 tools discussed
○ plus VALJOGen, POJOmatic, Eclipse wizards and IntelliJ wizards
● Good project to play with each tool
Summary
✯
Summary
● All four tools have their sweet spot and trade off
○ AutoValue - simplicity, abstract class
○ Immutables - comprehensive, abstract class or interface
○ Lombok - almost a language extension, hacky implementation
○ Joda-Beans - C# style properties, runtime dependency
Summary - personal view
● Use Joda-Beans if you like properties
○ Code should be valid on checkout
○ Immutable beans should be final
○ Want C# style properties
○ Hence I wrote and use Joda-Beans
● Otherwise, use Immutables
@jodastephen
http://blog.joda.org

Code generating beans in Java

  • 1.
    Bean generation Stop writinggetters and setters Stephen Colebourne, @jodastephen Engineering Lead, OpenGamma September 2016 http://blog.joda.org
  • 2.
    Stephen Colebourne ● JavaChampion, regular conference speaker ● Best known for date & time - Joda-Time and JSR-310 ● More Joda projects - http://www.joda.org ● Major contributions in Apache Commons ● Blog - http://blog.joda.org ● Worked at OpenGamma for 6 years
  • 3.
    Strata, from OpenGamma ●Open Source market risk library ● Valuation and risk calcs for finance ○ interest rate swap, FRA, CDS ● Great example of Java SE 8 coding style http://strata.opengamma.io/
  • 4.
  • 5.
    Why use beans? ●Beans are used in most applications ● Common denominator between applications & libraries ● ORMs (Hibernate, JPA, etc.) ● Serialization (Binary, JSON, XML, etc.) ● Mappers/configuration (Spring, Dozer, etc.)
  • 6.
    What is abean? ● JavaBean specification v1.01, from 1997 ● Focus on software components, COM/DCOM ● Manipulated visually in GUIs ● Java components within MS Word/Excel !!! ● References to floppy disks !!!
  • 7.
    What is abean? ● JavaBeans must extend java.awt.Component ● Created via standard factories ● No use of casts of instanceof checks ● Checked exceptions, not unchecked ● Communication via events ● Very specific rules around capitalization ● Use of BeanInfo and PropertyEditor
  • 8.
    What is abean? "Bean" != JavaBean
  • 9.
    What is amutable bean? ● Each tool has subtly different definition ● Most agree on ○ no-args constructor ○ getters match getXxx() ○ setters match setXxx() ○ equals() / hashCode() / toString()
  • 10.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for mutable bean /** Represents a person. */ public class Person { /** The forename of the person. */ private String forename; /** The surname of the person. */ private String surname; /** The birth date of the person. */ private LocalDate birthDate;
  • 11.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for mutable bean /** Creates an empty instance of Person. */ public Person() {} /** Gets the forename of the person. */ public String getForename() { … } /** Sets the forename of the person. */ public void setForename(String forename) { … } // same for surname/birthDate
  • 12.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for mutable bean /** Compares this person to another. */ public boolean equals(Object obj) { … } /** Returns a suitable hash code. */ public int hashCode() { … } /** Returns a string summary of this object. */ public String toString() { … }
  • 13.
    What is animmutable bean? ● "Beans" has traditionally implied mutability ● Many tools can't handle immutable beans ● No setters, may have "withers" ● Class must be final, with final fields ● Factory or builder instead of constructor
  • 14.
    Why immutable? ● Thread-safe ●Java Memory Model guarantees ● No need to trust other methods not to modify ● State checked and valid on construction ● Nulls can be eliminated
  • 15.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for immutable bean /** Represents a person. */ public final class Person { /** The forename of the person. */ private final String forename; /** The surname of the person. */ private final String surname; /** The birth date of the person. */ private final LocalDate birthDate;
  • 16.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for immutable bean /** Obtains an instance of Person. */ public Person of( String surname, String forename, LocalDate date) { … } /** Gets the forename of the person. */ public String getForename() { … } /** Returns a copy with the specified forename. */ public Person withForename(String forename) { … } // same for surname/birthDate
  • 17.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Pattern for immutable bean /** Compares this person to another. */ public boolean equals(Object obj) { … } /** Returns a suitable hash code. */ public int hashCode() { … } /** Returns a string summary of this object. */ public String toString() { … }
  • 18.
    Pattern for immutablebean ● May prefer to have a builder instead of a factory // factory Person person = Person.of("Stephen", "Colebourne", date); // or builder Person person = Person.builder() .forename("Stephen") .surname("Colebourne") .birthDate(date) .build();
  • 19.
    What is aVALJO? ● POJO - Plain Old Java Object ● VALJO - Value Java Object ○ http://blog.joda.org/2014/03/valjos-value-java-objects.html ● No use of identity - equal is interchangeable ● Immutable bean with extra restrictions ○ may be suitable for conversion to value types in Java 10/11 ○ logical state clearly defined and used in equals()/hashCode() ○ comparable consistent with equals() ○ constructor must be private ○ formal string representation that can be parsed
  • 20.
  • 21.
    How to createbeans ● Lots of different ways to create beans ● Best option depends on use case ● Mutable vs Immutable
  • 22.
    Option 1 -Manual ● Write each bean manually ● Deathly boring ● Double deathly boring for immutable beans ● Error-prone ● Probably not tested or code reviewed
  • 23.
    Option 2 -Another JVM language ● Kotlin code much shorter // Kotlin immutable bean data class Person( val forename: String, val surname: String, val birthDate: LocalDate)
  • 24.
    Option 2 -Another JVM language ● Groovy code much shorter // Groovy mutable bean class Customer { String forename String surname LocalDate birthDate
  • 25.
    Option 3 -Language change ● New language feature in Java ● Perhaps like Kotlin/Groovy ● Doesn't help us now ● Likely to be restrictive
  • 26.
    Option 4 -IDE generation ● Eclipse / IntelliJ / NetBeans can generate the code ○ Eclipse uses Ctrl+Alt+S followed by R / O / H / S ○ IntelliJ uses Alt+Insert ● One time generation, doesn't handle change ● Can you express field is not null? ● Can you generate immutable builders? ● Still not tested or code reviewed
  • 27.
    Option 5 -Use a tool ● AutoValue ● Immutables ● Lombok ● Joda-Beans ● (VALJOGen) ● (POJOmatic)
  • 28.
  • 29.
    AutoValue ● Annotation processor ●Open Source, from Google ○ https://github.com/google/auto/tree/master/value
  • 30.
    Annotation processing ● Additionalstep during compilation ● Compiler calls annotation processor ● Processor generates additional files ● If generated file is a .java file then it is compiled
  • 31.
  • 32.
    Annotation processing ● Maven ○just add the dependency ● Eclipse with Maven ○ install m2e-apt plugin ○ turn it on in the preferences ● IntelliJ with Maven ○ turn it on in the preferences
  • 33.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); AutoValue: your code @AutoValue public abstract class Person { public static Person of(String name, LocalDate date) { return new AutoValue_Person(name, date); } public abstract String getName(); public abstract LocalDate getBirthDate(); }
  • 34.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); AutoValue: generated @Generated("com.google.auto.value.processor.AutoValueProcessor") final class AutoValue_Person extends Person { private final String name; private final LocalDate birthDate; // constructor, getters, equals, hashCode, toString
  • 35.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); AutoValue builder: your code @AutoValue public abstract class Person { public static Builder builder() { return new AutoValue_Person.Builder(); } @AutoValue.Builder public static abstract class Builder { public abstract Builder name(String name); public abstract Builder birthDate(LocalDate date); public abstract Person build(); } public abstract Builder toBuilder();
  • 36.
    AutoValue options ● Handlesname() or getName() convention ● Can override (underride) equals/hashCode/toString ● Can add any other method ● Can change fields to nullable using @Nullable ● Supports memoized fields ● Builder can have sub-builders for collections ● Pattern to handle builder validation ● Extensions API, but undocumented
  • 37.
    AutoValue pros/cons ● Callersuse Person like a normal bean ○ but they can see class is abstract ● Generated code is package scoped ○ you must write outline builder and/or static factory method ○ quite a lot of code still to write ● Simple, does sensible thing for most use cases ○ not that many options ● Only for immutable beans
  • 38.
  • 39.
    Immutables ● Annotation processor ●Open Source ○ https://immutables.github.io/ ● Reacts to use Guava if available
  • 40.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Immutables: your code @Value.Immutable public interface Person { String getName(); LocalDate getBirthDate(); }
  • 41.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Immutables: generated @SuppressWarnings("all") @Generated({"Immutables.generator", "ImmutablePerson"}) public final class ImmutablePerson implements Person { private final String name; private final LocalDate birthDate; private ImmutablePerson(String name, LocalDate birthDate) { this.name = name; this.birthDate = birthDate; } // getters, withers, equals, hashCode, toString, builder
  • 42.
    Immutables options ● Cangenerate from abstract class or interface ● Handles name() or getName() convention ● Can override (underride) equals/hashCode/toString ● Can add any other method ● Pre-computed hash code ● Instance interning ● and lots more!
  • 43.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Immutables: hide implementation @Value.Immutable @Value.Style(visibility = PACKAGE) public abstract class Person extends WithPerson { public String getName(); public LocalDate getBirthDate(); public static class Builder implements ImmutablePerson.Builder {} }
  • 44.
    Immutables pros/cons ● Manyoptions and ways to generate ○ takes time to choose best option ● Callers see and use generated class (by default) ○ hiding generated class possible if you write more code ● Mutable beans supported ○ more like builders, do not follow JavaBeans spec
  • 45.
  • 46.
    Lombok ● Internal APIs ●Open Source ○ https://projectlombok.org/ ● Uses agents and annotation processors ● Works best with Eclipse, but requires installing
  • 47.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Lombok: your code - mutable @Data public class Person { private String name; private LocalDate birthDate; }
  • 48.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Lombok: generated- mutable @Data public class Person { private String name; private LocalDate birthDate; // constructor, getters, setters, equals, hashCode, toString }
  • 49.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Lombok: your code - immutable @Value public class Person { private String name; private LocalDate birthDate; }
  • 50.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Lombok: generated - immutable @Value public final class Person { private final String name; private final LocalDate birthDate; // constructor, getters, equals, hashCode, toString, builder }
  • 51.
    Lombok options ● Over15 annotations and tweaks ● Use other annotations for more control ● Can add any other method
  • 52.
    Lombok pros/cons ● Nosecond class, proper immutable bean ○ resulting bean is exactly the same as manually written ● Works best with Maven and Eclipse ○ installation in Eclipse not via a standard plugin ● Uses internal API hackery ○ higher risk option ● Generated code is invisible ○ cannot step in when debugging ○ can "delombok" to code generated code
  • 53.
  • 54.
    Joda-Beans ● Same-file regenerator ●Open Source, by me @jodastephen ○ http://www.joda.org/joda-beans/ ● Adds autogenerated block to your code ● Generation using Maven/Gradle, on-save in Eclipse
  • 55.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Joda-Beans: your code - mutable @BeanDefinition public class Person implements Bean { @PropertyDefinition private String name; @PropertyDefinition private LocalDate birthDate; }
  • 56.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Joda-Beans: generated - mutable @BeanDefinition public class Person implements Bean { @PropertyDefinition private String name; @PropertyDefinition private LocalDate birthDate; // ---- AUTOGENERATED START ---- // getters, setters, equals, hashCode, toString, properties // ----- AUTOGENERATED END ----- }
  • 57.
    Properties ● C# andmost other languages have properties ● Higher level than a field ● Bean is a set of properties ● Can list, get and set properties ○ like reflection ● Very useful abstraction for frameworks
  • 58.
    Joda-Beans properties ● Beanprovides abstraction for properties ● MetaBean acts like Class ● Can loop over MetaProperty for each property ○ meta bean acts as a hash-map of property name to property ○ no reflection ● BeanBuilder allows a bean to be created ○ this allows immutable beans to be created one property at a time
  • 59.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Joda-Beans: your code immutable @BeanDefinition public class Person implements ImmutableBean { @PropertyDefinition(validate = "notNull") private String name; @PropertyDefinition(validate = "notNull") private LocalDate birthDate; }
  • 60.
    // Java 7 List<Person>people = loadPeople(); Collections.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); Joda-Beans: generated immutable @BeanDefinition public class Person implements ImmutableBean { @PropertyDefinition(validate = "notNull") private String name; @PropertyDefinition(validate = "notNull") private LocalDate birthDate; // ---- AUTOGENERATED START ---- // getters, equals, hashCode, toString, properties, builder // ----- AUTOGENERATED END ----- }
  • 61.
    Joda-Beans options ● Annotationsallow field-level and bean-level control ● Control scope/style for getters/setters ● Supports pragmatic optional usage ● Can add any validation code ● Defaults/cross-validation for immutable bean builders ● Can default one property from another in builder ● Can fully override constructor
  • 62.
    Joda-Beans pros/cons ● Nosecond class, proper immutable bean ○ resulting bean is same as manually written ● Adds abstraction for properties without reflection ○ key reason to use Joda-Beans, but requires runtime dependency ● Built in XML, JSON, Binary serialization ● Generated code is visible for debugging ○ more code to checkin, but easy to ignore in review ○ proper Javadoc ● Plugin for Maven, Gradle and Eclipse with M2E ○ anyone want to volunteer to write an IntelliJ one?
  • 63.
  • 64.
    Comparisons ● Annotation processor ○AutoValue ○ Immutables ● Internal APIs ○ Lombok ● Same file regenerator ○ Joda-Beans
  • 65.
    Comparisons ● All cangenerate a lot of useful code ○ getters, factories, builders, equals, hashCode, toString ● Some can generate mutable beans ● Only Joda-Beans generates C# style properties ● Each project has a different trade-off
  • 66.
    Same class vsGenerated class ● Same class (Joda-Beans, Lombok) ○ your code involves writing fields ○ caller sees concrete class ○ properly immutable ● Generated class (AutoValue, Immutables) ○ your code involves writing methods (more code) ○ caller sees abstract class or interface ○ is it really immutable? ○ IDE rename class typically breaks code
  • 67.
    Collections ● Immutable beansshould use Guava ImmutableList ● Builder needs to take List and convert internally ● All except Lombok do this correctly
  • 68.
    Installation requirements ● AutoValue& Immutables use annotation processor ○ must be configured in IDE, extra plugin for Eclipse ● Lombok uses internal API hackery ○ requires specific Eclipse installation ● Joda-Beans runs as separate code regenerator ○ for Eclipse, just needs standard M2E
  • 69.
    AutoValue vs Immutables ●AutoValue ○ you write abstract class ○ generated class is package-scoped ○ cannot generate static factory ○ must write builder outline manually ● Immutables ○ you write interface or abstract class ○ generated class is public (can be made private or package-scoped) ○ static factory and builder in generated class ○ lots of flexibility
  • 70.
    Valid on checkout ●AutoValue, Immutables, Lombok ○ code invalid in IDE on checkout unless configured ○ only your code checked in ● Joda-Beans ○ code valid in IDE on checkout, even if not configured ○ your code and generated code checked in
  • 71.
    Evaluate yourself ● GitHubproject with everything setup for comparison ○ https://github.com/jodastephen/compare-beangen ● Includes 4 tools discussed ○ plus VALJOGen, POJOmatic, Eclipse wizards and IntelliJ wizards ● Good project to play with each tool
  • 72.
  • 73.
    Summary ● All fourtools have their sweet spot and trade off ○ AutoValue - simplicity, abstract class ○ Immutables - comprehensive, abstract class or interface ○ Lombok - almost a language extension, hacky implementation ○ Joda-Beans - C# style properties, runtime dependency
  • 74.
    Summary - personalview ● Use Joda-Beans if you like properties ○ Code should be valid on checkout ○ Immutable beans should be final ○ Want C# style properties ○ Hence I wrote and use Joda-Beans ● Otherwise, use Immutables @jodastephen http://blog.joda.org