O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

Code generating beans in Java

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Carregando em…3
×

Confira estes a seguir

1 de 74 Anúncio
Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

Anúncio

Semelhante a Code generating beans in Java (20)

Mais recentes (20)

Anúncio

Code generating beans in Java

  1. 1. Bean generation Stop writing getters and setters Stephen Colebourne, @jodastephen Engineering Lead, OpenGamma September 2016 http://blog.joda.org
  2. 2. 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
  3. 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. 4. Introduction ⇒
  5. 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. 6. 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 !!!
  7. 7. 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
  8. 8. What is a bean? "Bean" != JavaBean
  9. 9. 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()
  10. 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. 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. 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. 13. 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
  14. 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. 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. 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. 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. 18. 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();
  19. 19. 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
  20. 20. Creating beans
  21. 21. How to create beans ● Lots of different ways to create beans ● Best option depends on use case ● Mutable vs Immutable
  22. 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. 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. 24. Option 2 - Another JVM language ● Groovy code much shorter // Groovy mutable bean class Customer { String forename String surname LocalDate birthDate
  25. 25. Option 3 - Language change ● New language feature in Java ● Perhaps like Kotlin/Groovy ● Doesn't help us now ● Likely to be restrictive
  26. 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. 27. Option 5 - Use a tool ● AutoValue ● Immutables ● Lombok ● Joda-Beans ● (VALJOGen) ● (POJOmatic)
  28. 28. AutoValue
  29. 29. AutoValue ● Annotation processor ● Open Source, from Google ○ https://github.com/google/auto/tree/master/value
  30. 30. 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
  31. 31. Annotation processing Person (abstract) PersonImpl (concrete) Compilation finds annotations and code generates You write abstract class
  32. 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. 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. 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. 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. 36. 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
  37. 37. 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
  38. 38. Immutables
  39. 39. Immutables ● Annotation processor ● Open Source ○ https://immutables.github.io/ ● Reacts to use Guava if available
  40. 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. 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. 42. 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!
  43. 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. 44. 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
  45. 45. Lombok
  46. 46. Lombok ● Internal APIs ● Open Source ○ https://projectlombok.org/ ● Uses agents and annotation processors ● Works best with Eclipse, but requires installing
  47. 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. 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. 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. 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. 51. Lombok options ● Over 15 annotations and tweaks ● Use other annotations for more control ● Can add any other method
  52. 52. 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
  53. 53. Joda-Beans
  54. 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. 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. 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. 57. 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
  58. 58. 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
  59. 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. 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. 61. 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
  62. 62. 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?
  63. 63. Comparisons
  64. 64. Comparisons ● Annotation processor ○ AutoValue ○ Immutables ● Internal APIs ○ Lombok ● Same file regenerator ○ Joda-Beans
  65. 65. 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
  66. 66. 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
  67. 67. Collections ● Immutable beans should use Guava ImmutableList ● Builder needs to take List and convert internally ● All except Lombok do this correctly
  68. 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. 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. 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. 71. 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
  72. 72. Summary ✯
  73. 73. 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
  74. 74. 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

×