Spring Basics: @Conditional Bean Wiring

Table of Contents

A Use Case for Conditional Bean Wiring

Suppose we want to enable caching for our web application. We are interested to find out whether this helps our application or whether the overhead will so big that it actually slows our application down. We decide we want to put the new functionality behind a feature toggle. We add a new property to our application called app.caching.enabled=false. When we are ready to enable the caching, we change the property’s value to true and we are in business. When the results disappoint, we can easily revert the property’s value to false.

@Conditional Introduction

The @Conditional annotation can be used on any type or method that declares a bean:

@Conditional(SomeCondition.class)
@Bean
public SomeBean someBean() {
    return new SomeBean();
}

@Conditional takes a mandatory class that implements the functional interface Condition. Condition defines a single method matches that returns a boolean. The method decides whether the bean should be loaded into the Spring context or whether it should be ignored:

public SomeCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        /* make decision based on context and metadata */
    }
}

A @Conditional @Configuration

When @Conditional is applied to a class which is also annotated with @Configuration, then all of the @Bean methods, @Import, @ComponentScan and other annotations will be subject to the condition. This means that when the condition evaluates to false, all of the configuration defined in that class will be ignored.

Since creating a cache carries costs with it (even an unused cache reserves space on the heap for its initial size), this is exactly what we want in our situation.

@Configuration
@Conditional(CacheCondition.class)
public class CacheConfig {

    /* ... define cache manager and caches here ... */

    public static CacheCondition implements ConfigurationCondition {
        public ConfigurationPhase getConfigurationPhase() {
            return ConfigurationPhase.PARSE_CONFIGURATION;
        }

        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().getRequiredProperty("app.caching.enabled", Boolean.class);
        }
    }
}

Since we are dealing with a conditional configuration instead of a regular bean, the condition class implements ConfigurationCondition instead of Condition. The ConfigurationCondition makes us implement another method that specifies at which point the condition should be evaluated. Normally, this ConfigurationPhase is set to REGISTER_BEAN, which means it checks the condition when adding a regular bean. In this case, we want it set to PARSE_CONFIGURATION, which makes Spring evaluate the condition at the moment the configuration class is parsed. If the condition does not match at that moment, the @Configuration class will not be added to the context.

Dependencies

The only dependency is on spring-context:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.1.RELEASE</version>
</dependency>

Sample Project

A sample project can be found on GitLab.

Spring Basics: Dynamically Inject Values With Spring’s @Value

Table of Contents

If we do not want to hard-code values into our source code, we can use properties files. With the @Value annotation, Spring gives us an easy means to get properties from properties files and inject them into our code.

Dependencies

This post was written with Spring 5.0.5.RELEASE and Java 1.8.0_181.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

Inject Scalars

Let’s say we have the following key-value pairs in a file app.properties:

app.string.property=hello
app.integer.property=987
app.floating.point.property=3.14159
app.boolean.property=false

To get access to these properties, we declare an application configuration in Java:

@Configuration
@ComponentScan
@PropertySource("app.properties")
public class AppConfig {}

The @PropertySource adds a property source to Spring’s Environment. Here, the properties file is placed in the root of the classpath (and since I am using Maven default paths, that would be src/main/resources.

package com.relentlesscoding.wirebeans;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class HabitTest {

    @Value("${app.string.property}")
    private String stringProperty;

    @Value("${app.integer.property}")
    private int integerProperty;

    @Value("${app.floating.point.property}")
    private float floatingPointProperty;

    @Value("${app.boolean.property}")
    private boolean booleanProperty;

    @Test
    public void stringProperty() {
        assertThat(stringProperty, is("hello"));
    }

    @Test
    public void integerProperty() {
        assertThat(integerProperty, is(987));
    }

    @Test
    public void floatingPointProperty() {
        assertThat(floatingPointProperty, is(3.14159F));
    }

    @Test
    public void booleanProperty(){
        assertThat(booleanProperty, is(false));
    }
}

Injecting Complex Values

Let’s say we also have collections of values in our properties file:

app.collection.strings.property=one, two, three
app.collection.floats.property=1.2, 3.4, 5.6
app.collection.dates.property=2018-09-30T10:00:00, 2018-09-29T11:00:00, 2018-09-28T12:00:00

By default, Spring won’t be able to interpret Lists of values. The best we can do, by default, is getting an array of Strings:

@Value("${app.collection.strings.property}")
private String[] stringArrayProperty;

@Test
public void stringsArrayProperty() {
    assertArrayEquals(new String[]{"one", "two", "three"}, stringArrayProperty);
}

Declare a ConversionService to Inject Collections And Other Complex Types

To convert properties to other types than strings, we need to enable Spring’s ConversionService.

@Bean
public static ConversionService conversionService() {
    return new DefaultFormattingConversionService();
}

We instantiate DefaultFormattingConversionService, which is “configured by default with converters and formatters appropriate for most applications”. That means that it can convert comma-separated strings to common, generic collection types, and can convert strings to dates, currencies and TimeZones, for example.

Notice that the method is declared static. ConversionService is of type BeanFactoryPostProcessor and must be instantiated very early in the Spring container lifecycle, so that its services are available when processing of annotations such as @Autowired and @Value are done. By declaring the method static, the ConversionService can be invoked without instantiating the enclosing @Configuration class. Therefore, we can use @Value (and other annotations) that make use of this converter in the same class, without running into the trouble that ConversionService is not yet instantiated.

To learn more about bean instantiation, read the part under “BeanFactoryPostProcessor-returning @Bean methods”. Also, this answer on StackOverflow is very clarifying.

@Test
public void floatArrayProperty() {
    assertArrayEquals(new float[]{1.2F, 3.4F, 5.6F}, floatArrayProperty, 0.01F);
}

To convert dates from a properties string to actual date objects we need an extra step: @DateTimeFormat. This annotation indicates the format of the date to Spring. In this case, we format our property strings to conform to ISO-8601 or DateTimeFormat.ISO.DATE_TIME:

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@Value("${app.collection.dates.property}")
private List<LocalDate> listOfDatesProperty;

@Test
public void listOfDatesProperty() {
    assertThat(listOfDatesProperty.size(), is(3));
    assertEquals(LocalDate.parse("2018-09-30T10:00:00", DateTimeFormatter.ISO_DATE_TIME), listOfDatesProperty.get(0));
}

Thanks to our ConversionService, we can now convert not only to arrays, but also to collections.

Inject Maps With Spring’s @Value

If we throw in a Spring Expression Language (SpEL) expression, we can even have dictionaries in our properties and convert them to Maps:

app.collection.map.string.to.integer={one:"1", two:"2", three:"3"}
@Value("#{${app.collection.map.string.to.integer}}")
private Map<String, Integer> mapStringToInteger;

@Test
public void mapProperty() {
    assertThat(mapStringToInteger.size(), is(3));
    assertEquals(new Integer(1), mapStringToInteger.get("one"));
    assertEquals(new Integer(2), mapStringToInteger.get("two"));
    assertEquals(new Integer(3), mapStringToInteger.get("three"));
}

Notice the #{...} that delimits the SpEL expression. It evaluates the string that comes from the properties files and parses it to a Map. To understand how this works, let’s have a look at what a literal map in a SpEL expression would look like:

@Value("#{{1: 'Catch-22', 2: '1984', 3: 'Pride and Prejudice'}}")
private Map<Integer, String> books;

A literal map in a SpEL expression is delimited by braces {key: 'value', ...}. This is exactly what we had in our properties file.

Spring Basics: XML Setter Injection With Custom Method Names

In a previous blog post we ended up with the following XML-based configuration:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="firstStreak" class="com.relentlesscoding.wirebeans.PositiveStreak">
        <constructor-arg ref="startTime"/>
    </bean>
    <bean id="secondStreak" class="com.relentlesscoding.wirebeans.PositiveStreak">
        <constructor-arg ref="startTime"/>
    </bean>

    <util:list id="myRunningStreaks">
        <ref bean="firstStreak"/>
        <ref bean="secondStreak"/>
    </util:list>

    <bean id="running" class="com.relentlesscoding.wirebeans.Running">
        <property name="streaks" ref="myRunningStreaks"/>
    </bean>

</beans>

The complete code can be found on GitLab.

To recap, we instantiate a bean of type LocalDate by invoking its now() static method. We inject this bean into two PositiveStreak beans using constructor injection. We reference the LocalDate bean by its id, startTime. Next, we create a bean that is a list of PositiveStreaks using the util namespace. We then inject this list into a Habit class called Running using setter injection.

For setter injection to work from XML, the setter method needs to follow Java bean conventions. This means that there should be setter method called set<PropertyName>, where the important part is that the method start with set. The name of the property itself can be something completely different from the field it is setting, Spring does not care. For example, the following would work without a hitch:

class Running implements Habit {
    private List<Streak> myStreakList;

    public void setStreaks(List<Streak> aListOfStreaks) {
        this.myStreakList = aListOfStreaks;
    }
}
<bean class="com.relentlesscoding.wirebeans.Running">
    <property name="streaks" ref="myRunningStreaks" />
</bean>

The only important thing is that the name attribute of the property element corresponds to the Property part of setProperty setter method in Java. To reiterate: The name of the field that is being set by the mutator method can be something completely different from the name attribute of the property element.

But sometimes we want to be creative with our method names if that makes the code more readable, or maybe we are dealing with code that we cannot change. If we end up with a mutator method that does not start with set, you are now in a position to appreciate that Spring will not find this method and throws a BeanCreationException.

Handling Mutators With a Non-Standard Names

On StackOverflow a solution was proposed that uses a MethodInvokingFactoryBean. But since we are invoking a method that does not return a result, the documentation recommends we use MethodInvokingBean instead.

Suppose we have the follow setter in place:

class Running implements Habit {
    private List<Streak> myStreakList;

    public void replaceStreaks(List<Streak> aListOfStreaks) {
        this.myStreakList = aListOfStreaks;
    }
}

We could leverage a MethodInvokingBean like so:

<bean id="running" class="com.relentlesscoding.wirebeans.Running">

<bean id="caller" class="org.springframework.beans.factory.config.MethodInvokingBean">
    <property name="targetObject" ref="running"/>
    <property name="targetMethod" value="replaceStreaks"/>
    <property name="arguments" ref="myRunningStreaks"/>
</bean>

(Notice that we actually use setter injection on the MethodInvokingBean by specifying properties on it.) The targetObject attribute specifies on which instance a targetMethod should be invoked. We can specify our custom mutator name, and pass a reference to our arguments.

This is verbose, so think carefully before you violate the Java bean naming convention. Consider using a facade if the code is not under your control. Alternatively, Java-based Spring configuration with the @Autowired annotation will work on a method with any name.

Spring Basics: Wiring Beans with XML Configuration

If you have to work with legacy Spring applications, chances are you will have know how XML-based configuration works. Although Java configuration is preferred for new applications, sometimes you just don’t have a choice.

The Code

You can find the code from this blog post on GitLab.

Dependencies

The only dependency you need to get a Spring container running is spring-context. Add in Maven:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

Declaring Beans in XML

The following class will become a bean:

package com.relentlesscoding.wirebeans;

import java.util.List;

public class Running implements Habit {
    private final String name = "Running";
    private final String description = "Run 10 km every day";
    private List<Streak> streaks;

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public List<Streak> getStreaks() {
        return streaks;
    }

    public void setStreaks(List<Streak> streaks) {
        this.streaks = streaks;
    }

    public void addStreak(Streak streak) {
        streaks.add(streak);
    }
}

Create an XML file, give it any name (I would call it applicationContext.xml) and place it in your src/main/resources.

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="running" class="com.relentlesscoding.wirebeans.Running"/>
</beans>

This would wire a bean with the id running that is of type Running (which is a Habit). You can see why this is much more of a hassle to set up than using a simple @Component annotation on a class or a @Bean annotation in a @Configuration class. Those XML namespaces are nasty, but luckily most IDEs will help you with them.

Injecting Beans

To inject dependencies, we have two choices:

  • Constructor injection
  • Setter injection

Unlike with Java configuration, we cannot insert into fields when using XML-based configuration.

Constructor Injection

Suppose we want to insert one bean into another bean, for instance a HabitRepository that persists habits to the database into a HabitService. By using the <constructor-arg /> element and the ref property, we can accomplish this:

<bean id="habitRepository" class="com.relentlesscoding.wirebeans.HabitRepository" />

<bean id="habitService" class="com.relentlesscoding.wirebeans.HabitService">
    <constructor-arg ref="habitRepository" />
</bean>

If we wanted to pass more arguments to the HabitService constructor, we must keep on eye on the order: it must be the same as the order in which they are declared in the class.

To ease working with constructor arguments and as a way to curtail the verbosity of the XML configuration, Spring offers the c XML namespace to help wire beans without the need to create a sub-element <constructor-arg />:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="currentTime" class="java.time.LocalDate" factory-method="now" />

    <bean id="streak"
        class="com.relentlesscoding.wirebeans.PositiveStreak"
        c:startTime-ref="currentTime" />

We define a bean of type java.time.LocalDate and we use the static factory method now() to get an instance of it. We then use the c namespace to pass it to the constructor of our PositiveStreak bean. c:startTime-ref="currentTime" should be read as: pass the reference to the bean with id currentTime to the constructor argument that has the name startTime.

So we can reference constructor arguments by name. We can also reference them by position. c:_0-ref="currentTime" would do the exact same thing. XML does not allow a digit as the first character of an attribute, so we have to use an underscore. If there is only a single argument to the constructor, we can even use the shorthand c:_-ref="currentTime". I would not want to promote this as readable, but it’s good to know it exists and might be used in the wild.

Read more about the c namespace here.

Setter Injection

To use setter injection with XML-based configuration, you use the <property> element. If you look back at the Running class above, you see it has a method setStreak that takes a List<Streak>:

<bean id="startTime" class="java.time.LocalDate" factory-method="now" />

<bean id="streak"
    class="com.relentlesscoding.wirebeans.PositiveStreak"
    c:_0-ref="startTime" />

<bean id="running" class="com.relentlesscoding.wirebeans.Running">
    <property name="streaks">
        <list>
            <ref bean="streak" />
        </list>
    </property>
</bean>

The <property> element has an attribute name that refers to the field name of the bean being set. In the current case, class Running has a field named streaks. As a child element of <property> we define a list of Streak references.

For a list of literal String values, this would have looked like:

<property name="listOfStrings">
    <list>
        <value>string value 1</value>
        <value>string value 1</value>
        <value><null/></value>
    </list>
</property>

The list is wired with literal Strings and even a literal null.

Spring also provides the p namespace to make this more convenient (less verbose):

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="streak"
        class="com.relentlesscoding.wirebeans.PositiveStreak"
        c:_0-ref="startTime" />

    <bean id="running"
        class="com.relentlesscoding.wirebeans.Running"
        p:streaks-ref="streak" />
</beans>

The usage of the p namespace is a lot like that of the c namespace. In this case, p:streaks-ref="streak" tells spring to wire a property named streaks with the bean that is referenced by the id streak. Now, the property streaks takes a List. If we pass only a single element to that list, the current syntax works and Spring will happily insert the single reference to streak into a List for us and pass that to the setter method. If we want to pass more than one element in a list, however, we have to create the list separately first, and then pass the id of that reference to the p property:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="firstStreak" class="com.relentlesscoding.wirebeans.PositiveStreak" c:_0-ref="startTime"/>
    <bean id="secondStreak" class="com.relentlesscoding.wirebeans.PositiveStreak" c:_0-ref="startTime"/>

    <util:list id="myRunningStreak">
        <ref bean="firstStreak"/>
        <ref bean="secondStreak"/>
    </util:list>

    <bean id="running" class="com.relentlesscoding.wirebeans.Running" p:streaks-ref="myRunningStreak"/>
</beans>

We need to add the util namespace and the location of the util schema definition to get this to work. You see that the XML becomes quite verbose the more you try to do with it. The util namespace allows us to create collections of literal values or beans. These collections can then be referenced by their id.

More information:

Taking the App for a Test Ride

package com.relentlesscoding.wirebeans;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class HabitTest {

    @Autowired
    Habit runningHabit;

    @Test
    public void runningHabitIsNotNull() {
        Assert.assertNotNull(runningHabit);
    }

    @Test
    public void runningHabitHasSingleStreak() {
        Assert.assertEquals(2, runningHabit.getStreaks().size());
    }
}

To run integration tests where the Spring context is available, you need the following dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.5.RELEASE</version>
    <scope>test</scope>
</dependency>

spring-test contains the SpringRunner JUnit runner, and the @ContextConfiguration that will tell Spring where to look for the application context that contains the beans that need to be wired. In this case, we tell it to look at the applicationContext.xml that we put in src/main/resources, so we can reference it by looking at the root of our classpath with the attribute locations = "classpath:applicationContext.xml".

How to write a custom appender in log4j2?

/* package declaration, imports... */

@Plugin(name = "CustomListAppender",
        category = Core.CATEGORY_NAME,
        elementType = Appender.ELEMENT_TYPE,
        printObject = true)
public final class CustomListAppender extends AbstractAppender {

    // for storing the log events
    private List<LogEvent> events = new ArrayList<>();

    protected CustomListAppender(
            String name,
            Filter filter,
            Layout<? extends Serializable> layout,
            boolean ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions);
    }

    @Override
    public void append(LogEvent event) {
        if (event instanceof MutableLogEvent) {
            events.add(((MutableLogEvent) event).createMemento());
        } else {
            events.add(event);
        }
    }

    public List<LogEvent> getEvents() {
        return events;
    }

    @PluginFactory
    public static CustomListAppender createAppender(
            @PluginAttribute("name") String name,
            @PluginElement("Layout") Layout<? extends Serializable> layout,
            @PluginElement("Filter") Filter filter) {
        if (name == null) {
            LOGGER.error("No name provided for TestLoggerAppender");
            return null;
        }

        if (layout == null) layout = PatternLayout.createDefaultLayout();

        return new CustomListAppender(name, filter, layout, true);
    }
}

Our CustomListAppender extends AbstractAppender, because that implements a lot of the methods from the Appender interface for us that we would otherwise have to implement ourselves.

The @Plugin annotation identifies this class a plugin that should be picked up by the PluginManager:

  • The name attribute defines the name of the appender that can be used in the configuration.
  • The category attribute should be "Core", because “Core plugins are those that are directly represented by an element in a configuration file, such as an Appender, Layout, Logger or Filter” (source). And we are creating an appender.
  • The elementType attribute defines which type of element in the Core category this plugin should be. In our case, "appender".
  • The printObject attribute defines whether our custom plugin class defines a useful toString() method. We do, because the AbstractAppender class we’re extending is taking care of that for us.

We implement the Appender#append(LogEvent) method to add each event to our events list. If the LogEvent happens to be mutable, we must take care to create an immutable copy of the event, otherwise subsequent log events will overwrite it (we will get a list of, say, three log events that are all referencing the same object). We also add a simple getter method to retrieve all log events.

For the PluginManager to create our custom plugin, it needs a way to instantiate it. log4j2 uses a factory method for that, indicated by the annotation @PluginFactory. An appender contains attributes, such as a name, and other elements, such as layouts and filters. To allow for these, we use the corresponding annotations @PluginAttribute to indicate that a parameter represents an attribute, and @PluginElement to indicate that a parameter represents an element.

To log errors that might occur during this setup, we can make use of the StatusLogger. This logger is available as LOGGER, and is defined in one of the parents of our custom plugin, AbstractLifeCycle. (The level of log messages that should be visible can be adjusted in the <Configuration status="warn" ...> element.)

Configuration

Configuration:
  packages: com.relentlesscoding.logging.plugins
  status: warn
  appenders:
    Console:
      name: STDOUT
    CustomListAppender:
      name: MyVeryOwnListAppender

  Loggers:
    logger:
      -
        name: com.relentlesscoding.logging
        level: info
        AppenderRef:
          ref: MyVeryOwnListAppender
    Root:
      level: error
      AppenderRef:
        ref: STDOUT

The packages attribute on the Configuration element indicates the package that should be scanned by the PluginManager for custom plugins during initialization.

How to use our custom list appender?

private CustomListAppender appender;

@Before
public void setupLogging() {
    LoggerContext context = LoggerContext.getContext(false);
    Configuration configuration = context.getConfiguration();
    appender = configuration.getAppender("MyVeryOwnListAppender");
    appender.getEvents().clear();
}

When we run tests now, we are able to see all logged events by calling appender.getEvents(). Before each test, we take care to clear the list of the previous log statements.

I like my method pointers with curry in Groovy

Invoking a method several times can easily be done in Java in a loop. But what if we have several methods that need to be executed several times? Since Java does not feature pointers to functions, we cannot pass functions around, and cannot create a generic method that takes a pointer to a method and executes it. This is where Groovy shines.

Suppose we want to check on the status of some external system or work. We want to check the status every half a second for a maximum of ten times in total.

// the generic type in Closure<Boolean> indicates its return type
boolean isOperationSuccessful(int numOfTries, Closure<Boolean> action) {
    Thread.sleep(500)
    for (i in 0..<numOfTries) {
        if (action()) {
            return true
        } else {
            Thread.sleep(500)
        }
    }
}

// we can pass closures...
def check = { int n -> new Random().nextInt(10) == n }
println isOperationSuccessful(10, check.curry(3))

// ... as well as methods
boolean isWorkDone(int id) {
    // check if particular external system identified by `id` is done
    return new Random().nextInt(2) == 1
}
// `.&` is the method pointer operator
println isOperationSuccessful(5, this.&isWorkDone.curry(1))

We can pass methods around by referencing them with the method pointer operator .&:

def pointerToUpper = 'hello world'.&toUpperCase
assert pointerToUpper() == 'HELLO WORLD'

By using Groovy’s take on currying, we can fix parameters of a closure (or method):

def power(double n, int exponent) { n ** exponent }
def squared = this.&power.rcurry(2)
assert squared(12) == 144

rcurry fixes the right-most argument of the method, curry the left-most. (And yes, there is also an index-based method: ncurry). Both return a new Closure that takes one less argument.

How to ignore an invalid SSL certificate in Java?

Sometimes during development it is useful to use a certificate whose CN (Common Name) does not match the host name in the URL, for example localhost. In these cases Java will throw a SSLHandshakeException. How can we easily disable certificate checking for localhost and other domains of our choosing?

Your own certificate checking

The easiest way is to create your own class that implements the interface HostnameVerifier:

WhitelistHostnameVerifier.java

package com.relentlesscoding.https;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.util.HashSet;
import java.util.Set;

// singleton
enum WhitelistHostnameVerifier implements HostnameVerifier {
    // these hosts get whitelisted
    INSTANCE("localhost", "sub.domain.com");

    private Set whitelist = new HashSet<>();
    private HostnameVerifier defaultHostnameVerifier =
            HttpsURLConnection.getDefaultHostnameVerifier();

    WhitelistHostnameVerifier(String... hostnames) {
        for (String hostname : hostnames) {
            whitelist.add(hostname);
        }
    }

    @Override
    public boolean verify(String host, SSLSession session) {
        if (whitelist.contains(host)) {
            return true;
        }
        // important: use default verifier for all other hosts
        return defaultHostnameVerifier.verify(host, session);
    }
}

Main.java

// use our HostnameVerifier for all future connections
HttpsURLConnection.setDefaultHostnameVerifier(
        WhitelistHostnameVerifier.INSTANCE);
final String url = "https://relentlesscoding.com";
HttpsURLConnection conn =
        (HttpsURLConnection) new URL(url).openConnection();
System.out.println(conn.getResponseCode());

HttpsURLConnection.DefaultHostnameVerifier#verify always returns false, so we might as well return false ourselves, but this way the code will keep working when the implementation of HttpsURLConnection changes.

Note: you can set the default HostnameVerifier globally by using the static method setDefaultHostnameVerifier, or you can set it per instance, using conn.setHostnameVerifier.

Problems with Let’s Encrypt certificates

One thing I found out while testing this, was that OpenJDK version 1.8.0_131 won’t correctly handle Let’s Encrypt certificates:

java.io.IOException: HTTPS hostname wrong: should be <relentlesscoding.com>

This is due to the fact that Let’s Encrypt certificates are not present in the Java installation. Upgrading to version 1.8.0_141 resolves this (for Oracle versions >= 8U101 or >= 7U111).

Whitelisting, NOT disabling certificate checking

The best approach here is whitelisting. This will keep the certificate checking in place for most sites, and will only disable it for pre-approved hosts. I saw quite a bit of examples online that disable certificate checking completely, by writing the verify method as follows:

public boolean verify(String hostname, SSLSession session) {
    return true;
}

This is not secure, as it completely ignores all invalid certificates.

Creating custom Intershop ISML functions with CustomTag

The problem

I wanted to capitalize a certain value from the pipeline dictionary in an ISML template. Intershop provides ISML functions of the kind ucase and lcase to transform a string to uppercase or lowercase respectively. When the value of the dictionary name Product:Name is AwesomeNotebook:

<isprint value="#ucase(Product:Name)#">

this will print AWESOMENOTEBOOK. Unfortunately, a similar function to capitalize a string is not provided by Intershop. Ideally, you would want to be able to implement your own methods, so that you could type:

<isprint value="#capitalize(Product:Name)#">

What about custom modules?

Intershop does provide the ability to create custom modules. These are basically just tags you can give whatever name you like, and you can provide an implementation in Java or ISML. The interface is defined in a modules.isml file. You could, for example, define a custom tag isprintdefault that prints a default value whenever the value passed to it is null or the empty string:

<isprintdefault default="(unknown)" value="#Product:Price">

This would print (unknown) every time Product:Price does not contain a value.

This solution, however, has two drawbacks:

  • For a Java implementation, this would come down to writing scriptlet. A few lines of scriptlet is fine ofcourse, but as the size of the code increases, it becomes harder and harder to maintain, because there is no compilation-time check and debugging is nearly impossible (say hello to a thousand print statements).
  • Also, it is cumbersome for implementing something like the capitalize function mentioned above, because you would have to provide the input to the custom module, put the result in the pipeline dictionary, and then use the pipeline dictionary name:
<iscapitalize dictname="capitalizedStr" input="#Product:Name#">
<isprint value="#capitalizedStr#">

Instead of just using the returned capitalized string directly:

<isprint value="#capitalize(Product:Name)#">

Solution: ISML Custom Tag

An ISML custom tag looks just like a custom module:

<ISUUID name="CategoryRenderEntityID">

(Incidently, this creates a UUID and stores it in the pipeline dictionary variable name CategoryRenderEntityID). According to the documentation, the difference between a custom tag and a custom module is that the former “provides a significant performace increase” compared to the latter.

Two purposes

Custom tags can be used for two purposes:

  • Performing a single operation, like we saw with the ISUUID custom tag above, where the tag performs a single action (creating a new UUID and putting it in the pipeline dictionary).
  • Inserting an instance of a helper or utilities class into the pipeline dictionary.

Creating an ISML Custom Tag

Say, we want to create an ISML Custom Tag named <ishelper>. First, we would define it in a modules.properties file, located at <cartridge>/staticfiles/cartridge/config/modules.properties:

ismodules.helper.class=custom_base.internal.modules.Helper
ismodules.helper.isStrict=false
ismodules.helper.parameters=alias
ismodules.helper.parameter.alias.type=java.lang.String
ismodules.helper.parameter.alias.isRequired=false

The class property should point to the implementing Java class. Since a pipeline dictionary is available to custom tags, we can define whether we want a clean, strict dictionary or not, much like we can do in pipelines. Parameters and return values can be defined by providing their name, type and whether or not they are mandatory.

So, the properties file above defines a custom tag <ishelper> (put a leading is to your lowercase class name), that has an optional attribute alias of type String. Other parameters can be added by using comma’s:

ismodules.helper.parameters=alias,more,params

Don’t forget to also add a type and whether the parameter is required or not. The type of the parameter can be any Java class, so you’re not limited to just strings.

The Java class with the implementing code must extend the abstract class CustomTag. It is required to override the method processOpenTag, which will be called every time the custom tag is encountered in the ISML template.

Now then, we can create “custom ISML functions” by adding an instance of our Helper class to the pipeline dictionary:

public class Helper extends CustomTag {
    @Override
    public void processOpenTag(PageContext paramPageContext,
                               ServletResponse paramServletResponse,
                               AbstractTemplate paramAbstractTemplate,
                               int paramInt)
            throws IOException, ServletException
    {
        PipelineDictionary dict = AbstractTemplate
                .getTemplateExecutionConfig()
                .getPipelineDictionary();
        String alias = dict.getOptional("alias", "Helper");
        dict.put(alias, new Helper());
    }
}

If we wanted a function capitalize in our templates, we could add such a method to our Java class:

public String getCapitalize(String str) {
    /* do groundbreaking stuff */
    return capitalizedStr;
}

Note that the method name should start with get in order for it to be available in the pipeline dictionary in our templates. We can now use the method as follows:

<isprint value="#Helper:Capitalize(Product:Name)#">

Don’t forget, however, to add the custom tag somewhere at the beginning of the template before using it:

<ishelper alias="MyCustomUtilsClass">
<!-- snip -->
<isloop iterator="MyProducts" alias="product">
    <isprint value="#MyCustomUtilsClass:Capitalize(product:Name)#"
</isloop>

(Note that the alias attribute is optional. If you leave it out, it will default to Helper: see the implementation above. This will be the alias of the class we’re using to invoke methods on:

<isprint value="#MyCustomUtilsClass:noArgMethod()#">

Remember that the name of the actual class that contains the custom tag is part of the tag name: ishelper.)

Alternative method of making a Java class available in the pipeline dictionary

Obviously, we do not have to rely on an ISML custom tag to put an instance of a Java class in the pipeline dictionary. We could just create a pipelet that does this, and put this pipelet in a pipeline that gets called a lot (a Prefix pipeline would be good). This would remove the need to put <ishelper> (or whatever we named the custom tag) at the top of our templates. But the helper class would only be available if the Prefix pipeline was called, so you would need to check that carefully. Putting the custom tag at the top of the template makes the import explicit and easily verifiable.

A word of caution

Custom tags are very handy, but they extend the internal CustomTag class. This means Intershop does not encourage using them in custom project development. In fact, you won’t find any information about them in the documentation.

Java stateful sessions or: how to properly send cookies with each redirect request

The problem

I needed to login to some webpage programmatically. It happened to be one of those pages where, when the login succeeds, the user is redirected to another page, and then to another (something along the lines of ‘Please login’ -> ‘You are successfully logged in’ -> ‘Admin panel’). So I needed to write something that would store the cookies that come along with each response, and send those cookies out with each subsequent request. With curl, I would have used:

$ curl --location --cookie-jar logincookie 'https://login.securepage.com'

So how can we mock this behavior in Java?

Java SE’s CookieHandler

A simple DuckDuckGo search will show Java SE’s own java.net.CookieHandler: pretty neat, a built-in solution! The CookieHandler, as the name suggests, will handle all your floating-point arithmetic. Just kidding, it will serve as the object where the HTTP protocol handler (used by objects such as URL) will go to to check for relevant cookies. CookieHandler is a global abstract class that will handle the state management of all requests.

CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);

CookieManager’s task is to decide which cookies to accept and which to reject. CookiePolicy.ACCEPT_ALL will accept all cookies. Other choices include CorkiePolicy.ACCEPT_NONE (no cookies will be accepted) and CookiePolicy.ACCEPT_ORIGINAL_SERVER (only cookies from the original server will be accepted).

If you want, you can also create a CookieManager with a specific CookieStore and specify exactly where your cookies will be stored. This is needed, for example, to create persistent cookies that can be restored after a JVM restart. By default, CookieManager will create an in-memory cookie store.

To install our own system-wide cookie handler, we invoke CookieHandler.setDefault and pass our CookieManager as an argument.

The tutorial on the Oracle website does a pretty decent job of explaining everything in more detail.

If this works for you, great! If not, keep on reading.

Apache HttpComponent Client to the rescue

Unfortunately, the steps above did not work for me as the server kept complaining that the session was invalid after the redirects. After reading somewhere on StackOverflow that Java SE’s version of the CookieStore was buggy, and me being on a deadline, I decided to turn my attention to Apache and their HttpComponent Client (version 4.5.3):

import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
// ... other imports

class Downloader {
    private CookieStore cookieStore = new BasicCookieStore();

    private void doLogin() {
        // CookieSpecs.STANDARD is the RFC 6265 compliant policy
        RequestConfig requestConfig = RequestConfig
                .custom()
                .setCookieSpec(CookieSpecs.STANDARD)
                .build();

        // automatically follow redirects
        CloseableHttpClient client = HttpClients
                .custom()
                .setRedirectStrategy(new LaxRedirectStrategy())
                .setDefaultRequestConfig(requestConfig)
                .setDefaultCookieStore(cookieStore)
                .build();

        String addr = "https://login.securehost.com";
        HttpPost post = new HttpPost();

        // login and password as payload for POST request
        List<NameValuePair> urlParams = new ArrayList<>();
        urlParams.add(new BasicNameValuePair("login", "neftas"));
        urlParams.add(new BasicNameValuePair("password", "letmein"));
        post.setEntity(new UrlEncodedFormEntity(urlParams));

        HttpResponse response = client.execute(post);
        // ... and we are logged in!
    }
}

(To keep the code clean, I’ve not bothered with any exception handling.)

The RequestConfig serves to indicate what kind of cookie policy we want (there are several, unfortunately). If you just want things to work, you can start with CookieSpecs.STANDARD, which is compliant with “a more relaxed profile defined by RFC 6265”.

During the creation of the HttpClient, we specify that we want to follow all redirects (setRedirectStrategy(new LaxRedirectStrategy())), we pass the cookie policy we defined earlier in the RequestConfig, and lastly, we pass the cookie store.

Adding a file to the root of your Gradle distribution

A while ago, I needed to write a program that retrieved some information from the database by using SQL queries located in files. I wanted to add a file that would contain the settings of the app, like the port, SID, login and password for the database, but also the location of those queries. The problem was I couldn’t add those settings to a file in the standard src/groovy/resources folder, because when creating a distribution with Gradle ./gradlew distZip the file would be part of the jar, and thus it would be difficult to modify the contents. I was basically after a run-control file, a settings file in the root of my distribution, that I could easily change on each run (if necessary).

Gradle provides several ways to accomplish this:

  1. Add the file to src/dist and the file will be put in the root of the distribution after invoking ./gradlew installDist. Any folders you create will also be put in the distribution, so you can create src/dist/config, for example, to put your configuration in, and a folder config will be created in the distribution.
  2. Indicate to Gradle that you want a certain file or folder copied:

    applicationDistribution.from('config.properties') {
        into ''
    }
    
  3. Use the distribution plugin:

    apply plugin: 'distribution'
    
    distributions {
        main {
            contents {
                from {
                    'settings.groovy'
                }
            }
        }
    }