Java 8 Lambdas vs Groovy Closures Compactness: Grouping And Summing

Java 8 is featuring lambdas, which are similar to a construction Groovy has already for some time: closures.

In Groovy we could already do this:

def list = ['a', 'b', 'c']
print list.collect { it.toUpperCase() }
// [A, B, C]

where { it.toUpperCase() } is the closure.

In Java 8 we can achieve the same functionality now in a concise way.

list.stream().map( s -> s.toUpperCase() )

Although you could argue that with proper use of the new Stream API, bulk operations and method references, at least the intent of a piece of code is conveyed more clearly now – Java’s verboseness can still cause sore eyes.

Here are some other examples.

class Animal {
    String name
    BigDecimal price
    String farmer
    String toString() { name }
}

def animals = []
animals << new Animal(name: "Buttercup", price: 2, farmer: "john")
animals << new Animal(name: "Carmella", price: 5, farmer: "dick")
animals << new Animal(name: "Cinnamon", price: 2, farmer: "dick")

Example 1: Summing the total price of all animals

assert 9 == animals.sum { it.price }
// or animals.price.sum()

What Groovy you see here:

  • sum can be called on a List and optionally passed a closure defining the property of “it” – the animal being iterated over – to sort on.
  • or sum can be called on a List without any arguments, which is equivalent to invoking the “plus” method on all items in the collection.
Optional<BigDecimal> sum =
	animals.
		stream().
		map(Animal::getPrice).
		reduce((l, r) -> l.add(r));
assert BigDecimal.valueOf(9) == sum.get();

What Java you see here:

  • Through the Stream API’s stream method we can create a pipeline of operations, such as map and reduce
  • The argument to the map operation is a method reference to the getPrice() method of the currently iterated animal. We could also replace this part with the expression a -> a.getPrice()
  • reduce is a general reduction operation (also called a fold) in which the BigDecimals of the prices are added up. This is also giving us an Optional with the total sum.
  • BTW, if we were to use a double for price – which we don’t because I want to give a good example – we could have used an existing DoubleStream with a sum() on it e.g.
    double sum = animals.stream().mapToDouble(Animal::getPrice).sum();
    

Example 2: Grouping all animals by farmer

def animalsByFarmer = animals.groupBy { it.farmer }
// [john:[Buttercup], dick:[Carmella, Cinnamon]]
Map<String, List<Animal>> animalsByFarmer =
	animals
		.stream()
		.collect(
			Collectors.groupingBy(Animal::getFarmer));
// {dick=[Carmella, Cinnamon], john=[Buttercup]}

Example 3: Summing the total price of all animals grouped by farmer

def totalPriceByFarmer =
    animals
        .groupBy { it.farmer }
        .collectEntries { k, v -> [k, v.price.sum()] }
// [john:2, dick:7]

What Groovy you see here:

  • collectEntries iterates through the “groupBy” map transforming each map entry using the k, v -> ... closure returning a map of the transformed entries. v.price is actually a List of prices (per farmer) – such as in example 1 – on which we can call sum().
Map<String, BigDecimal> totalPriceByFarmer =
	animals
		.stream()
		.collect(
			Collectors.groupingBy(
				Animal::getFarmer,
				Collectors.reducing(
					BigDecimal.ZERO,
					Animal::getPrice,
					BigDecimal::add)));
// {dick=7, john=2}

This Java code again yields the same results. Since IDE’s, Eclipse at least, don’t format this properly, you’ll have to indent these kinds of constructions for readability a bit yourself.

Grails 2.4 Released: Installing Groovy-Eclipse Compiler 2.3 in Eclipse/GGTS

GGTS logoThis month has been interesting: on the 7th Groovy 2.3.0 has been released, followed up by Grails 2.4 a few days ago. Great work!

UPDATE: GGTS 3.6.0 M1 has been released, which already includes support for Groovy 2.3.

If you’re an Eclipse or Groovy/Grails Tool Suite (GGTS) user, you might want to install the Groovy/Eclipse Compiler to have the IDE make use of all the Groovy 2.3 features. Now if you’ve downloaded the latest GGTS version – which at the moment is 3.5.1 – and created a brand new Grails 2.4 project, the Markers view might have alerted you to the following:

Groovy: compiler mismatch Project level is: 2.3 Workspace level is 2.1
Groovy compiler level expected by the project does not match workspace compiler level.

Consequently, also 1 Java problem is reported about a java.lang.NoSuchMethodError in an AssetMethodTagLib.groovy of the new Asset Pipeline Plugin shipping with Grails 2.4

You might be tempted to follow the Quick Fix and set the project to 2.3 but the settings screen doesn’t allow you to select 2.3 yet.

No Groovy 2.3 compiler

Fix it by installing the Groovy Compiler 2.3 for Groovy/Eclipse.

Installing the Groovy Compiler in GGTS

  1. Inside GGTS, on the Spring Dashboard go to Manage > IDE Extensions.
  2. Search for the keyword “groovy”, find the Groovy 2.3 Compiler for Groovy-Eclipse
  3. Select it and press Install. Restart when asked.

Installing the Groovy Compiler in GGTS (alternative) or Eclipse

  1. Inside GGTS/Eclipse, go to Help > Install New Software…
  2. Work with the snapshot Update Site of the Groovy/Eclipse project: http://dist.springsource.org/snapshot/GRECLIPSE/e4.3/
  3. Under Extra Groovy compilers (Optional) mark Groovy Compiler 2.3 Feature
  4. Install. Continue. Restart when asked.

After installation the compiler became the default for the entire workspace.

Groovy 2.3 installed

And you’re done. Problems are gone. Go work on your new Grails application :-)

Mockito

Mockito: Why You Should Not Use InjectMocks Annotation to Autowire Fields

People like the way how Mockito is able to mock Spring’s auto-wired fields with the @InjectMocks annotation. When I read this post of Lubos Krnac last week, I thought I should explain why I think the use of InjectMocks is a bad signal and how you should avoid it. Hint: it’s about visibility.

Let’s say we have a PlannerServiceImpl which delegates to a PlannerClient. Uses Spring for auto-wiring all together; there’s no constructor, but Spring is able to use field injection.

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    @Autowired
    private PlannerClient plannerClient;

    @Override
    public Long createWeddingPlan() {
        try {
            CreateWeddingPlanResponse response = plannerClient.createWeddingPlan();
            return convert(response).getId();
        } catch (Exception e) {
            LOG.error("Unable to create wedding plan", e);
            return null;
        }
    }

An associated test could look like:

@RunWith(MockitoJUnitRunner.class)
public class PlannerServiceImplTest {

    @Mock
    private PlannerClient plannerClient;

    @InjectMocks
    private final PlannerServiceImpl plannerService = new PlannerServiceImpl();

    @Test
    public void testCreateWeddingPlanWhenClientReturnsUndefinedResponseThenNullIsReturned() throws Exception {
        when(plannerClient.createWeddingPlan()).thenReturn(null);

        final Long actual = plannerService.createWeddingPlan();

        assertThat(actual, is(nullValue()));
    }

The org.mockito.InjectMocks annotation can be seen as an equivalent of Spring’s own dependency injection. The Javadoc states:

Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won’t report failure; i.e. you will have to provide dependencies yourself.

(Whoever would design this to fail silently at all?)

So what if someone decides to create a new dependency, say an AuditService and upgrades a bunch of services by adding it as an additional property, also marked as @Autowired?

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    @Autowired
    private PlannerClient plannerClient;

    @Autowired
    private AuditService auditService;

    @Override
    public Long createWeddingPlan() {
        try {
            CreateWeddingPlanResponse response = plannerClient.createWeddingPlan();
            auditService.addEntry("Wedding plan created.");
            return convert(response).getId();
        }

The test will fail, probably on a NullPointerException on a missing AuditService – and it is not visible why. InjectMocks will fail silently and there’s no indication the test needs this. Did I already ask whoever would design something like this to fail silently?

If you’re doing TDD or not (and we are able to change the test first) – clients of this code don’t know about an additional dependency, because it’s completely hidden. You shouldn’t use InjectMocks to deal with injecting private fields (err..or at all) , because this kind of Dependency Injection is evil – and signals you should change your design.

There, I said it.

Fix #1: Solve your design and make your dependencies visible.

Create a constructor. Pass along the PlannerClient.

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    private final PlannerClient plannerClient;

    @Autowired
    public PlannerServiceImpl(final PlannerClient plannerClient) {
        this.plannerClient = plannerClient;
    }

Now, when there are more dependencies needed, they’re clearly in sight because the constructor says so. So don’t go creating a bunch of setters now – they still don’t force you to pass along your required dependencies!

@Service
public class PlannerServiceImpl implements PlannerService {
    private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);

    private final PlannerClient plannerClient;

    private final AuditService auditService;

    @Autowired
    PlannerServiceImpl(PlannerClient plannerClient, AuditService auditService) {
        this.plannerClient = plannerClient;
        this.auditService = auditService;
    }

The test itself won’t compile any more (luckily, because of the way we’ve been instantiating the field as plannerService = new PlannerServiceImpl()!) as soon as e.g. the AuditService is added to the constructor. So it’s time to..

Fix #2: Get rid of @InjectMocks

There’s no need to use @InjectMocks anymore. Instead instantiate the class-under-test properly in a @Before-annotated method – where it belongs, passing along all needed dependencies.

@RunWith(MockitoJUnitRunner.class)
public class PlannerServiceImplTest {

@Mock
private PlannerClient plannerClient;

@Mock
private AuditService auditService;

private PlannerServiceImpl plannerService;

@Before
void setUp() {
    plannerService = new PlannerServiceImpl(plannerClient, auditService);
}

Luckily, Lubos – which I mentioned earlier – completely independently came to the same conclusion in the mean time :-)