Saturday, December 20, 2014

Looking into the Java 9 Money and Currency API (JSR 354)

JSR 354 defines a new Java API for working with Money and Currencies, which is planned to be included in Java 9. In this post we will look at the current state of the reference implementation: JavaMoney.

Like my post about the Java 8 Date/Time API this post will be mainly driven by code that shows the new API.

But before we start, I want to quote a short section from the specification that pretty much sums up the motivation for this new API:

Monetary values are a key feature of many applications, yet the JDK provides little or no support. The existing java.util.Currency class is strictly a structure used for representing current ISO 4217 currencies, but not associated values or custom currencies. The JDK also provides no support for monetary arithmetic or currency conversion, nor for a standard value type to represent a monetary amount.

If you use Maven, you can easily try the current state of the reference implementation by adding the following dependency to your project:

<dependency>
  <groupId>org.javamoney</groupId>
  <artifactId>moneta</artifactId>
  <version>0.9</version>
</dependency>

All specification classes and interfaces are located in the javax.money.* package.
We will start with the two core interfaces CurrencyUnit and MonetaryAmount. After that, we will look into exchange rates, currency conversion and formatting.


CurrencyUnit and MonetaryAmount
CurrencyUnit models a currency. CurrencyUnit is very similar to the existing java.util.Currency class, except it allows custom implementations. According to the specification it should be possible that java.util.Currency implements CurrencyUnit. CurrencyUnit instances can be obtained using the MonetaryCurrencies factory:
// getting CurrencyUnits by currency code
CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
CurrencyUnit usDollar = MonetaryCurrencies.getCurrency("USD");

// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
MontetaryAmount represents a concrete numeric representation of a monetary amount. A MonetaryAmount is always bound to a CurrencyUnit. Like CurrencyUnit, MonetaryAmount is an interface that supports different implementations. CurrencyUnit and MonetaryAmount implementations must be immutable, thread safe, serializable and comparable.
// get MonetaryAmount from CurrencyUnit
CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
MonetaryAmount fiveEuro = Money.of(5, euro);

// get MonetaryAmount from currency code
MonetaryAmount tenUsDollar = Money.of(10, "USD");

// FastMoney is an alternative MonetaryAmount factory that focuses on performance
MonetaryAmount sevenEuro = FastMoney.of(7, euro);
Money and FastMoney are two MonetaryAmount implementations of JavaMoney. Money is the default implementation that stores number values using BigDecimal. FastMoney is an alternative implementation which stores amounts in long fields. According to the documentation  operations on FastMoney are 10-15 times faster compared to Money. However, FastMoney is limited by the size and precision of the long type.

Please note that Money and FastMoney are implementation specific classes (located in org.javamoney.moneta.* instead of javax.money.*). If you want to avoid implementation specific classes, you have to obtain a MonetaryAmountFactory to create a MonetaryAmount instance:
MonetaryAmount specAmount = MonetaryAmounts.getDefaultAmountFactory()
    .setNumber(123.45)
    .setCurrency("USD")
    .create();
Two MontetaryAmount instances are considered equal if the implementation classes, the currency units and the numeric values are equal:
MonetaryAmount oneEuro = Money.of(1, MonetaryCurrencies.getCurrency("EUR"));
boolean isEqual = oneEuro.equals(Money.of(1, "EUR")); // true
boolean isEqualFast = oneEuro.equals(FastMoney.of(1, "EUR")); // false
MonetaryAmount has various methods that allow accessing the assigned currency, the numeric amount, its precision and more:
MonetaryAmount monetaryAmount = Money.of(123.45, euro);
CurrencyUnit currency = monetaryAmount.getCurrency();
NumberValue numberValue = monetaryAmount.getNumber();

int intValue = numberValue.intValue(); // 123
double doubleValue = numberValue.doubleValue(); // 123.45
long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100
long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45
int precision = numberValue.getPrecision(); // 5

// NumberValue extends java.lang.Number. 
// So we assign numberValue to a variable of type Number
Number number = numberValue;

Working with MonetaryAmounts
Mathematical operations can be performed with MonetaryAmount:
MonetaryAmount twelveEuro = fiveEuro.add(sevenEuro); // "EUR 12"
MonetaryAmount twoEuro = sevenEuro.subtract(fiveEuro); // "EUR 2"
MonetaryAmount sevenPointFiveEuro = fiveEuro.multiply(1.5); // "EUR 7.5"

// MonetaryAmount can have a negative NumberValue
MonetaryAmount minusTwoEuro = fiveEuro.subtract(sevenEuro); // "EUR -2"

// some useful utility methods
boolean greaterThan = sevenEuro.isGreaterThan(fiveEuro); // true
boolean positive = sevenEuro.isPositive(); // true
boolean zero = sevenEuro.isZero(); // false

// Note that MonetaryAmounts need to have the same CurrencyUnit to do mathematical operations
// this fails with: javax.money.MonetaryException: Currency mismatch: EUR/USD
fiveEuro.add(tenUsDollar);
Rounding is another important part when working with money. MonetaryAmounts can be rounded using a rounding operator:
CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");
MonetaryAmount dollars = Money.of(12.34567, usd);
MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);
MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35
Here 12.3456 US Dollars are rounded with the default rounding for this currency.

When working with collections of MonetaryAmounts, some nice utility methods for filtering, sorting and grouping are available. These methods can be used together with the Java 8 Stream API.

Consider the following collection:
List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(2, "EUR"));
amounts.add(Money.of(42, "USD"));
amounts.add(Money.of(7, "USD"));
amounts.add(Money.of(13.37, "JPY"));
amounts.add(Money.of(18, "USD"));
We can now filter amounts by CurrencyUnit:
CurrencyUnit yen = MonetaryCurrencies.getCurrency("JPY");
CurrencyUnit dollar = MonetaryCurrencies.getCurrency("USD");

// filter by currency, get only dollars
// result is [USD 18, USD 7, USD 42]
List<MonetaryAmount> onlyDollar = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar))
    .collect(Collectors.toList());

// filter by currency, get only dollars and yen
// [USD 18, USD 7, JPY 13.37, USD 42]
List<MonetaryAmount> onlyDollarAndYen = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar, yen))
    .collect(Collectors.toList());
We can also filter out MonetaryAmounts smaller or greater than a specific threshold:
MonetaryAmount tenDollar = Money.of(10, dollar);

// [USD 42, USD 18]
List<MonetaryAmount> greaterThanTenDollar = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar))
    .filter(MonetaryFunctions.isGreaterThan(tenDollar))
    .collect(Collectors.toList());
Sorting works in a similar way:
// Sorting dollar values by number value
// [USD 7, USD 18, USD 42]
List<MonetaryAmount> sortedByAmount = onlyDollar.stream()
    .sorted(MonetaryFunctions.sortNumber())
    .collect(Collectors.toList());

// Sorting by CurrencyUnit
// [EUR 2, JPY 13.37, USD 42, USD 7, USD 18]
List<MonetaryAmount> sortedByCurrencyUnit = amounts.stream()
    .sorted(MonetaryFunctions.sortCurrencyUnit())
    .collect(Collectors.toList());
Grouping functions:
// Grouping by CurrencyUnit
// {USD=[USD 42, USD 7, USD 18], EUR=[EUR 2], JPY=[JPY 13.37]}
Map<CurrencyUnit, List<MonetaryAmount>> groupedByCurrency = amounts.stream()
    .collect(MonetaryFunctions.groupByCurrencyUnit());

// Grouping by summarizing MonetaryAmounts
Map<CurrencyUnit, MonetarySummaryStatistics> summary = amounts.stream()
    .collect(MonetaryFunctions.groupBySummarizingMonetary()).get();

// get summary for CurrencyUnit USD
MonetarySummaryStatistics dollarSummary = summary.get(dollar);
MonetaryAmount average = dollarSummary.getAverage(); // "USD 22.333333333333333333.."
MonetaryAmount min = dollarSummary.getMin(); // "USD 7"
MonetaryAmount max = dollarSummary.getMax(); // "USD 42"
MonetaryAmount sum = dollarSummary.getSum(); // "USD 67"
long count = dollarSummary.getCount(); // 3
MonetaryFunctions also provides reduction function that can be used to obtain the max, min and sum of a MonetaryAmount collection:
List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(10, "EUR"));
amounts.add(Money.of(7.5, "EUR"));
amounts.add(Money.of(12, "EUR"));

Optional<MonetaryAmount> max = amounts.stream().reduce(MonetaryFunctions.max()); // "EUR 7.5"
Optional<MonetaryAmount> min = amounts.stream().reduce(MonetaryFunctions.min()); // "EUR 12"
Optional<MonetaryAmount> sum = amounts.stream().reduce(MonetaryFunctions.sum()); // "EUR 29.5"

Custom MonetaryAmount operations
MonetaryAmount provides a nice extension point called MonetaryOperator. MonetaryOperator is a functional interface that takes a MonetaryAmount as input and creates a new MonetaryAmount based on the input.
// A monetary operator that returns 10% of the input MonetaryAmount
// Implemented using Java 8 Lambdas
MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> {
  BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class);
  BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1"));
  return Money.of(tenPercent, amount.getCurrency());
};

MonetaryAmount dollars = Money.of(12.34567, "USD");

// apply tenPercentOperator to MonetaryAmount
MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567
Some standard API features are implemented as MonetaryOperator. For example, the rounding features we saw above are implemented as MonetaryOperator.


Exchange rates
Currency exchange rates can be obtained using an ExchangeRateProvider. JavaMoney comes with multiple different ExchangeRateProvider implementations. The two most important implementations are ECBCurrentRateProvider and IMFRateProvider.
ECBCurrentRateProvider queries the European Central Bank (ECB) data feed for getting current exchange rates while IMFRateProvider uses International Monetary Fund (IMF) conversion rates.
// get the default ExchangeRateProvider (CompoundRateProvider)
ExchangeRateProvider exchangeRateProvider = MonetaryConversions.getExchangeRateProvider();

// get the names of the default provider chain
// [IDENT, ECB, IMF, ECB-HIST]
List<String> defaultProviderChain = MonetaryConversions.getDefaultProviderChain();

// get a specific ExchangeRateProvider (here ECB)
ExchangeRateProvider ecbExchangeRateProvider = MonetaryConversions.getExchangeRateProvider("ECB");
If no specific ExchangeRateProvider is requested a CompoundRateProvider will be returned. CompoundRateProvider delegates exchange rate requests to a chain of ExchangeRateProviders and returns the result from the first provider that returns an adequate result.
// get the exchange rate from euro to us dollar
ExchangeRate rate = exchangeRateProvider.getExchangeRate("EUR", "USD");

NumberValue factor = rate.getFactor(); // 1.2537 (at time writing)
CurrencyUnit baseCurrency = rate.getBaseCurrency(); // EUR
CurrencyUnit targetCurrency = rate.getCurrency(); // USD

Currency conversion
Conversion between currencies is be done with CurrencyConversions that can be obtained from ExchangeRateProviders:
// get the CurrencyConversion from the default provider chain
CurrencyConversion dollarConversion = MonetaryConversions.getConversion("USD");

// get the CurrencyConversion from a specific provider
CurrencyConversion ecbDollarConversion = ecbExchangeRateProvider.getCurrencyConversion("USD");

MonetaryAmount tenEuro = Money.of(10, "EUR");

// convert 10 euro to us dollar 
MonetaryAmount inDollar = tenEuro.with(dollarConversion); // "USD 12.537" (at the time writing)
Note that CurrencyConversion implements MonetaryOperator. Like other operators it can be applied using MonetaryAmount.with().

Formatting and parsing
MonetaryAmounts can be parsed/formatted from/to string using a MonetaryAmountFormat:
// formatting by locale specific formats
MonetaryAmountFormat germanFormat = MonetaryFormats.getAmountFormat(Locale.GERMANY);
MonetaryAmountFormat usFormat = MonetaryFormats.getAmountFormat(Locale.CANADA);

MonetaryAmount amount = Money.of(12345.67, "USD");

String usFormatted = usFormat.format(amount); // "USD12,345.67"
String germanFormatted = germanFormat.format(amount); // 12.345,67 USD

// A MonetaryAmountFormat can also be used to parse MonetaryAmounts from strings
MonetaryAmount parsed = germanFormat.parse("12,4 USD");
With AmountFormatQueryBuilder custom formats can be created:
// Creating a custom MonetaryAmountFormat
MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(
    AmountFormatQueryBuilder.of(Locale.US)
        .set(CurrencyStyle.NAME)
        .set("pattern", "00,00,00,00.00 ¤")
        .build());

// results in "00,01,23,45.67 US Dollar"
String formatted = customFormat.format(amount);
Note that the ¤ symbol (\u00A) is used as currency placeholder inside the pattern string.


Summary
We looked at many parts of the new Money and Currency API. The implementation already looks quite solid (but definitely needs some more documentation). I am looking forward to see this API in Java 9 :-)

You can find all the examples shown here on GitHub.

Share this post using Facebook, Twitter or Google+

Tuesday, October 14, 2014

Matching Latin characters with regular expressions

Recently I needed to check user input for non Latin characters. My first impression was that this cannot be done with regular expressions. It turned out that I was completely wrong.

Standard regular expression character classes like [a-zA-Z] or \w (word character) are not suitable for matching Latin characters, they are far too restrictive. For example, these classes exclude characters like öòóô or äáàâ which are used in many western and central European languages.

Luckily Java's java.regex.Pattern supports matching Unicode characters with \p. Various arguments can be passed with curly braces to \p. To match only Latin characters \p{IsLatin} can be used:
"öôóò".matches("\\p{IsLatin}+"); // matches
"Σήμε".matches("\\p{IsLatin}+"); // greek characters do not match
\p supports a wide range of Unicode scripts. It can be used to match Greek, Cyrillic, Braille and more.
Some examples:
"Σήμε".matches("^\\p{IsGreek}+$");
"ждля".matches("^\\p{IsCyrillic}+$");
"⠇⠏⠙⠟".matches("^\\p{IsBraille}+$");
"ᚊᚎᚑᚕᚙ᚛".matches("^\\p{IsOgam}+$");
Have a look at Character.UnicodeScript for the full list of supported scripts.

Share this post using Facebook, Twitter or Google+

Saturday, October 11, 2014

Injecting domain objects instead of infrastructure components

Dependency Injection is a widely used software design pattern in Java (and many other programming languages) that is used to achieve Inversion of Control. It promotes reusability, testability, maintainability and helps building loosely coupled components. Dependency Injection is the de facto standard to wire Java objects together, these days.
Various Java Frameworks like Spring or Guice can help implementing Dependency Injection. Since Java EE 6 there is also an official Java EE API for Dependency Injection available: Contexts and Dependency Injection (CDI).

We use Dependency Injection to inject services, repositories, domain related components, resources or configuration values. However, in my experience, it is often overlooked that Dependency Injection can also be used to inject domain objects.
A typical example of this, is the way the currently logged in user is obtained in Java many applications. Usually we end up asking some component or service for the logged in user.
The code for this might look somehow like the following snippet:
public class SomeComponent {

  @Inject
  private AuthService authService;
  
  public void workWithUser() {
    User loggedInUser = authService.getLoggedInUser();
    // do something with loggedInUser
  }
}
Here a AuthService instance is injected into SomeComponent. Methods of SomeComponent now use the AuthService object to obtain an instance of the logged in user.

However, instead of injecting AuthService we could inject the logged in user directly into SomeComponent.
This could look like this:
public class SomeComponent {

  @Inject
  @LoggedInUser
  private User loggedInUser;
  
  public void workWithUser() {
    // do something with loggedInUser
  }
}
Here the User object is directly injected into SomeComponent and no instance of AuthService is required. The custom annotation @LoggedInUser is used to avoid conflicts if more than one (managed) bean of type User exist.

Both, Spring and CDI are capable of this type of injection (and the configuration is actually very similar). In the following section we will see how domain objects can be injected using Spring. After this, I will describe what changes are necessary to do the same with CDI.

Domain object injection with Spring
To inject domain objects like shown in the example above, we only have to do two little steps.
First we have to create the @LoggedInUser annotation:
import java.lang.annotation.*;
import org.springframework.beans.factory.annotation.Qualifier;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface LoggedInUser {

}
Please note the @Qualifier annotation which turns @LoggedInUser into a custom qualifier. Qualifiers are used by Spring to avoid conflicts if multiple beans of the same type are available.

Next we have to add a bean definition to our Spring configuration. We use Spring's Java configuration here, the same can be done with xml configuration.
@Configuration
public class Application {

  @Bean
  @LoggedInUser
  @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public User getLoggedInUser() {
    // retrieve and return user object from server/database/session
  }
}
Inside getLoggedInUser() we have to retrieve and return an instance of the currently logged in user (e.g. by asking the AuthService from the first snippet). With @Scope we can control the scope of the returned object. The best scope depends on the domain objects and might differ among different domain objects. For a User object representing the logged in user, request or session scope would be valid choices. By annotating getLoggedInUser() with @LoggedInUser, we tell Spring to use this bean definition whenever a bean with type User annotated with @LoggedInUser should be injected.

Now we can inject the logged in user into other components:
@Component
public class SomeComponent {

  @Autowired
  @LoggedInUser
  private User loggedInUser;
  
  ...
}
In this simple example the qualifier annotation is actually not necessary. As long as there is only one bean definition of type User available, Spring could inject the logged in user by type. However, when injecting domain objects it can easily happen that you have multiple bean definitions of the same type. So, using an additional qualifier annotation is a good idea. With their descriptive name qualifiers can also act as documentation (if named properly).

Simplify Spring bean definitions
When injecting many domain objects, there is chance that you end up repeating the scope and proxy configuration over and over again in your bean configuration. In such a situation it comes in handy that Spring annotations can be used on custom annotations. So, we can simply create our own @SessionScopedBean annotation that can be used instead of @Bean and @Scope:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public @interface SessionScopedBean {

}
Now we can simplify the bean definition to this:
@Configuration
public class Application {

  @LoggedInUser
  @SessionScopedBean
  public User getLoggedInUser() {
    ...
  }
}
Java EE and CDI
The configuration with CDI is nearly the same. The only difference is that we have to replace Spring annotations with javax.inject and CDI annotations.

So, @LoggedInUser should be annotated with javax.inject.Qualifier instead of org.springframework.beans.factory.annotation.Qualifier (see: Using Qualifiers).
The Spring bean definition can be replaced with a CDI Producer method. Instead of @Scope the appropriate CDI scope annotation can be used.
At the injection point Spring's @Autowired can be replaced with @Inject.

Note that Spring also supports javax.inject annotations. If you add the javax.inject dependency to your Spring project, you can also use @Inject and @javax.inject.Qualifier. It is actually a good idea to do this because it reduces Spring dependencies in your Java code.

Conclusion
We can use custom annotations and scoped beans to inject domain objects into other components. Injecting domain objects can make your code easier to read and can lead to cleaner dependencies. If you only inject AuthService to obtain the logged in user, you actually depend on the logged in user and not on AuthService.
On the downside it couples your code stronger to the Dependency Injection framework, which has to manage bean scopes for you. If you want to keep the ability to use your classes outside a Dependency Injection container this can be a problem.
Which types of domain objects are suitable for injection highly depends on the application you are working on. Good candidates are domain objects you often use and which not depend on any method or request parameters. The currently logged in user is an object that might often be suitable for injection.

You can find the source of the shown example on GitHub.

Share this post using Facebook, Twitter or Google+

Wednesday, October 1, 2014

Checking for null values in Java with Objects.requiresNonNull()

Checking method/constructor parameters for null values is a common task problem in Java. To assist you with this, various Java libraries provide validation utilities (see Guava Preconditions, Commons Lang Validate or Spring's Assert documentation).
However, if you only want to validate for non null values you can use the static requiresNonNull() method of java.util.Objects. This is a little utility introduced by Java 7 that appears to be rarely known.

With Objects.requiresNonNull() the following piece of code
public void foo(SomeClass obj) {
  if (obj == null) {
    throw new NullPointerException("obj must not be null");
  }
  // work with obj
}
can be replaced with:
import java.util.Objects;

public void foo(SomeClass obj) {
  Objects.requireNonNull(obj, "obj must not be null");
  // work with obj
}


Share this post using Facebook, Twitter or Google+

Sunday, September 21, 2014

Reduce Boilerplate Code in your Java applications with Project Lombok


One of the most frequently voiced criticisms of the Java programming language is the amount of Boilerplate Code it requires. This is especially true for simple classes that should do nothing more than store a few values. You need getters and setters for these values, maybe you also need a constructor, overriding equals() and hashcode() is often required and maybe you want a more useful toString() implementation. In the end you might have 100 lines of code that could be rewritten with 10 lines of Scala or Groovy code. Java IDEs like Eclipse or IntelliJ try to reduce this problem by providing various types of code generation functionality. However, even if you do not have to write the code yourself, you always see it (and get distracted by it) if you open such a file in your IDE.

Project Lombok (don't be frightened by the ugly web page) is a small Java library that can help reducing the amount of Boilerplate Code in Java Applications. Project Lombok provides a set of annotations that are processed at development time to inject code into your Java application. The injected code is immediately available in your development environment.
Lets have a look at the following Eclipse Screenshot:

The defined class is annotated with Lombok's @Data annotation and does not contain any more than three private fields. @Data automatically injects getters, setters (for non final fields), equals(), hashCode(), toString() and a constructor for initializing the final dateOfBirth field. As you can see the generated methods are directly available in Eclipse and shown in the Outline view.

Setup
To set up Lombok for your application you have to put lombok.jar to your classpath. If you are using Maven you just have to add to following dependency to your pom.xml:
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.14.8</version>
  <scope>provided</scope>
</dependency>
You also need to set up Lombok in the IDE you are using:
  • NetBeans users just have to enable the Enable Annotation Processing in Editor option in their project properties (see: NetBeans instructions).
  • Eclipse users can install Lombok by double clicking lombok.jar and following a quick installation wizard.
  • For IntelliJ a Lombok Plugin is available.

Getting started
The @Data annotation shown in the introduction is actually a shortcut for various other Lombok annotations. Sometimes @Data does too much. In this case, you can fall back to more specific Lombok annotations that give you more flexibility.

Generating only getters and setters can be achieved with @Getter and @Setter:
@Getter
@Setter
public class Person {
  private final LocalDate birthday;
  private String firstName;
  private String lastName;

  public Person(LocalDate birthday) {
    this.birthday = birthday;
  }
}
Note that getter methods for boolean fields are prefixed with is instead of get (e.g. isFoo() instead of getFoo()). If you only want to generate getters and setters for specific fields you can annotate these fields instead of the class.

Generating equals(), hashCode() and toString():
@EqualsAndHashCode
@ToString
public class Person {
  ...
}
@EqualsAndHashCode and @ToString also have various properties that can be used to customize their behaviour:
@EqualsAndHashCode(exclude = {"firstName"})
@ToString(callSuper = true, of = {"firstName", "lastName"})
public class Person {
  ... 
}
Here the field firstName will not be considered by equals() and hashCode().
toString() will call super.toString() first and only consider firstName and lastName.

For constructor generation multiple annotations are available:
  • @NoArgsConstructor generates a constructor that takes no arguments (default constructor).
  • @RequiredArgsConstructor generates a constructor with one parameter for all non-initialized final fields.
  • @AllArgsConstructor generates a constructor with one parameter for all fields in the class.

The @Data annotation is actually an often used shortcut for @ToString, @EqualsAndHashCode, @Getter, @Setter and @RequiredArgsConstructor.

If you prefer immutable classes you can use @Value instead of @Data:
@Value
public class Person {
  LocalDate birthday;
  String firstName;
  String lastName;
}
@Value is a shortcut for @ToString, @EqualsAndHashCode, @AllArgsConstructor, @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) and @Getter.

So, with @Value you get toString(), equals(), hashCode(), getters and a constructor with one parameter for each field. It also makes all fields private and final by default, so you do not have to add private or final modifiers.


Looking into Lombok's experimental features
Besides the well supported annotations shown so far, Lombok has a couple of experimental features that can be found on the Experimental Features page.

One of these features I like in particular is the @Builder annotation, which provides an implementation of the Builder Pattern.
@Builder
public class Person {
  private final LocalDate birthday;
  private String firstName;
  private String lastName;
}
@Builder generates a static builder() method that returns a builder instance. This builder instance can be used to build an object of the class annotated with @Builder (here Person):
Person p = Person.builder()
  .birthday(LocalDate.of(1980, 10, 5))
  .firstName("John")
  .lastName("Smith")
  .build();

By the way, if you wonder what this LocalDate class is, you should have a look at my blog post about the Java 8 date and time API ;-)

Conclusion
Project Lombok injects generated methods, like getters and setters, based on annotations. It provides an easy way to significantly reduce the amount of Boilerplate code in Java applications.
Be aware that there is a downside: According to reddit comments (including a comment of the project author), Lombok has to rely on various hacks to get the job done. So, there is a chance that future JDK or IDE releases will break the functionality of project Lombok. On the other hand, these comments where made 5 years ago and Project Lombok is still actively maintained.

You can find the source of Project Lombok on GitHub.

Share this post using Facebook, Twitter or Google+

Friday, August 15, 2014

Understanding JUnit's Runner architecture

Some weeks ago I started creating a small JUnit Runner (Oleaster) that allows you to use the Jasmine way of writing unit tests in JUnit. I learned that creating custom JUnit Runners is actually quite simple. In this post I want to show you how JUnit Runners work internally and how you can use custom Runners to modify the test execution process of JUnit.

So what is a JUnit Runner?
A JUnit Runner is class that extends JUnit's abstract Runner class. Runners are used for running test classes. The Runner that should be used to run a test can be set using the @RunWith annotation.
@RunWith(MyTestRunner.class)
public class MyTestClass {

  @Test
  public void myTest() {
    ..
  }
}
JUnit tests are started using the JUnitCore class. This can either be done by running it from command line or using one of its various run() methods (this is what your IDE does for you if you press the run test button).
JUnitCore.runClasses(MyTestClass.class);
JUnitCore then uses reflection to find an appropriate Runner for the passed test classes. One step here is to look for a @RunWith annotation on the test class. If no other Runner is found the default runner (BlockJUnit4ClassRunner) will be used. The Runner will be instantiated and the test class will be passed to the Runner. Now it is Job of the Runner to instantiate and run the passed test class.

How do Runners work?
Lets look at the class hierarchy of standard JUnit Runners:
Runner is a very simple class that implements the Describable interface and has two abstract methods:
public abstract class Runner implements Describable {

  public abstract Description getDescription();

  public abstract void run(RunNotifier notifier);
}
The method getDescription() is inherited from Describable and has to return a Description. Descriptions contain the information that is later being exported and used by various tools. For example, your IDE might use this information to display the test results.
run() is a very generic method that runs something (e.g. a test class or a test suite).
I think usually Runner is not the class you want to extend (it is just too generous).

In ParentRunner things get a bit more specific. ParentRunner is an abstract base class for Runners that have multiple children. It is important to understand here, that tests are structured and executed in a hierarchical order (think of a tree).
For example: You might run a test suite which contains other test suites. These test suites then might contain multiple test classes. And finally each test class can contain multiple test methods.

ParentRunner has the following three abstract methods:
public abstract class ParentRunner<T> extends Runner implements Filterable, Sortable {    

  protected abstract List<T> getChildren();

  protected abstract Description describeChild(T child);

  protected abstract void runChild(T child, RunNotifier notifier);
}
Subclasses need to return a list of the generic type T in getChildren(). ParentRunner then asks the subclass to create a Description for each child (describeChild()) and finally to run each child (runChild()).

Now let's look at two standard ParentRunners: BlockJUnit4ClassRunner and Suite.

BlockJUnit4ClassRunner is the default Runner that is used if no other Runner is provided. So this is the Runner that is typically used if you run a single test class. If you look at the source of BlockJUnit4ClassRunner you will see something like this:
public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {

  @Override
  protected List<FrameworkMethod> getChildren() {
    // scan test class for methonds annotated with @Test
  }

  @Override
  protected Description describeChild(FrameworkMethod method) {
    // create Description based on method name
  }

  @Override
  protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
    if (/* method not annotated with @Ignore */) {
      // run methods annotated with @Before
      // run test method
      // run methods annotated with @After
    }
  }
}
Of course this is overly simplified, but it shows what is essentially done in BlockJUnit4ClassRunner.
The generic type parameter FrameworkMethod is basically a wrapper around java.lang.reflect.Method providing some convenience methods.
In getChildren() the test class is scanned for methods annotated with @Test using reflection. The found methods are wrapped in FrameworkMethod objects and returned. describeChildren() creates a Description from the method name and runChild() finally runs the test method.
BlockJUnit4ClassRunner uses a lot of protected methods internally. Depending on what you want to do exactly, it can be a good idea to check BlockJUnit4ClassRunner for methods you can override. You can have a look at the source of BlockJUnit4ClassRunner on GitHub.

The Suite Runner is used to create test suites. Suites are collections of tests (or other suites). A simple suite definition looks like this:
@RunWith(Suite.class)
@Suite.SuiteClasses({
  MyJUnitTestClass1.class,
  MyJUnitTestClass2.class,
  MyOtherTestSuite.class
})
public class MyTestSuite {}
A test suite is created by selecting the Suite Runner with the @RunWith annotation. If you look at the implementation of Suite you will see that it is actually very simple. The only thing Suite does, is to create Runner instances from the classes defined using the @SuiteClasses annotation. So getChildren() returns a list of Runners and runChild() delegates the execution to the corresponding runner.

Examples
With the provided information it should not be that hard to create your own JUnit Runner (at least I hope so). If you are looking for some example custom Runner implementations you can have a look at the following list:
 
Conclusion
JUnit Runners are highly customizable and give you the option to change to complete test execution process. The cool thing is that can change the whole test process and still use all the JUnit integration points of your IDE, build server, etc.
If you only want to make minor changes it is a good idea to have a look at the protected methods of BlockJUnit4Class runner. Chances are high you find an overridable method at the right location.

In case you are interested in Olaester, you should have a look at my blog post: An alternative approach of writing JUnit tests.

Share this post using Facebook, Twitter or Google+