Monday, December 27, 2010

Bookmark and Share

This is more a note to myself, but in case someone else wonders how to specify the active Maven profile in IntelliJ IDEA for projects containing several profiles, that's the way to go:

  • Open the "Maven Projects" window by selecting "Window" - "Tool Windows" - "Maven Projects"
  • Expand the "Profiles" node and select the profile you want to use
Bookmark and Share

One of the new features introduced with version 3.0 of the Spring framework is the Spring Expression Language or short "SpEL". This language is tailored for the needs when working with Spring and can be used when creating XML/annotation based Spring bean definitions for instance.

So I thought it would be nice if it was possible to use SpEL together with Hibernate Validator's @ScriptAssert constraint which allows to express validation routines using script or expression languages.

Unfortunately this does not work since currently no SpEL language binding for JSR 223 ("Scripting for the JavaTM Platform") exists. As @ScriptAssert's validator uses JSR 223 for expression evaluation at least for now SpEL can't be used along with @ScriptAssert (there is an issue in Spring's JIRA addressing this problem).

But as shown in previous posts it is very simple to create new constraint annotations for the Bean Validation API. So the idea is to build a new constraint @SpelAssert which resembles HV's @ScriptAssert but works with SpEL instead of the JSR 223 API.

Defining the annotation type is straight-forward:

1
2
3
4
5
6

7
8
9
10
11
12
13
14
15

@Target({ TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = SpelAssertValidator.class)
@Documented
public @interface SpelAssert {


    String message() default "{de.gmorling.moapa.bvspel.SpelAssert.message}";

    Class<?>[] groups() default {};


    Class<? extends Payload>[] payload() default {};

    String value();


}

Besides the standard attributes message(), groups() and payload() mandated by the BV specification we define one more attribute value(), which takes the SpEL expression to evaluate.

Now let's come to the validator:

1
2
3
4
5
6

7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
public class SpelAssertValidator implements

ConstraintValidator<SpelAssert, Object> {

    @Inject
    private ExpressionParser parser;

    private Expression expression;


    @Override
    public void initialize(SpelAssert constraintAnnotation) {

    String rawExpression = constraintAnnotation.value();


        if (rawExpression == null) {
            throw new IllegalArgumentException("The expression specified in @"

                + SpelAssert.class.getSimpleName() + " must not be null.");
        }

        expression = parser.parseExpression(rawExpression);
    }


    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {

        if (value == null) {

            return true;
        }

        return Boolean.TRUE.equals(expression.getValue(value, Boolean.class));

    }
}

In initialize() we use an ExpressionParser to parse the specified SpEL expression (so this happens only once) and evaluate the given object against it in isValid().

But wait a minute, where does the ExpressionParser come from, it is not instantiated here?

Right, the cool thing is Spring comes with it's own ConstraintValidatorFactory which performs dependency injection on constraint validators. A validator relying on that feature of course is not portable, but as this validator is based on SpEL and Spring anyways this is not an issue here.

In order to have this working a parser bean must be part of the Spring application context. We just register a SpelExpressionParser:

1

2
3
4
5
6
7
8
9
10

11
12
<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-3.0.xsd">

    <bean id="parser"
        class="org.springframework.expression.spel.standard.SpelExpressionParser"/>


    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>

This context also shows how to provide a BV Validator for dependency injection leveraging Spring's LocalValidatorFactoryBean.

Now let's have a look at the @SpelAssert constraint in action. The following shows the canonical example of a class CalendarEvent where the start date shall always be earlier than the end date:

1

2
3
4
5
6
7
8
9
10

@SpelAssert("startDate < endDate")
public class CalendarEvent {


    private Date startDate;

    private Date endDate;


    // getters, setters etc.

}

Note how SpEL allows dates to be compared using the "<" operator and that no alias for the evaluated bean is required, as all unqualified attribute/method names are resolved against the annotated object.

Finally we should have a test showing that the validator works as expected by validating a valid and an invalid CalendarEvent instance:

1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration
public class SpelAssertTest {

    @Inject
    private Validator validator;


    private Date startDate;
    private Date endDate;

    @Before

    public void setUpDates() {

        Calendar start = Calendar.getInstance();
        start.set(2010, 13, 24);

        startDate = start.getTime();

        Calendar end = Calendar.getInstance();
        end.set(2010, 13, 26);

        endDate = end.getTime();
    }

    @Test
    public void validEvent() {


        CalendarEvent event = new CalendarEvent();
        event.setStartDate(startDate);
        event.setEndDate(endDate);

        assertTrue(validator.validate(event).isEmpty());

    }

    @Test
    public void invalidEventYieldsConstraintViolation() {

        CalendarEvent event = new CalendarEvent();

        event.setStartDate(endDate);
        event.setEndDate(startDate);

        Set<ConstraintViolation<CalendarEvent>> violations = 
            validator.validate(event);

        assertEquals(1, violations.size());

        ConstraintViolation<CalendarEvent> violation = 
            violations.iterator().next();
        assertEquals(

            "SpEL expression \"startDate < endDate\" didn't evaluate to true.",
            violation.getMessage());
    }

}

The complete sources for this post can be found at GitHub, so don't hesistate to give it a try or use it in your projects if you like. Any feedback or ideas for improvement are warmly welcome.

Wednesday, November 17, 2010

Bookmark and Share
At my day job we are using the SVN property "svn:keywords" to let SVN replace the string "$Id$" with author name, revision number etc. within each Java source file.

One can add this property automatically when creating new files with the help of SVN's auto props feature. But from time to time someone, e.g. a new developer not knowing about auto props, checks in files without having the "svn:keywords" property set.

So I wondered how to identify such files in the repository. SVN doesn't provide a command answering that question, you only can retrieve all files having a certain property set.

But no problem, some shell magic to the rescue:

1
comm -23 <(sort <(sed 's/\.\///g' <(find . -name "*.java"))) <(sort <(sed 's/ - Id//g' <(svn propget svn:keywords * -R)))

So what's happening here? The basic idea is to list those files with the svn:keywords property set (svn propget) and compare this to a list with all files (find).

The outputs of both commands are brought into the same format using sed, sorted and then passed as parameters to the comm command, which compares two input files to each other. The -23 parameter causes only those lines to be put out which are only contained in file1 but not in file2, which are exactly the names of those files lacking the "svn:keywords" property.

I tested the command successfully on Mac OS X, but I think it should work pretty much the same way on other Unix systems, too.

Sunday, August 15, 2010

Bookmark and Share

While developing an Eclipse plug-in for a small spare-time project of mine I wondered where to find the sources of the Java Development Tools (JDT). They used to be part of the Eclipse RCP/plug-in developers package in previous releases, but this isn't the case anymore with Eclipse 3.6 (Helios).

After some googling I found the reason: as of release 3.6 the RCP distribution (now named "Eclipse for RCP and RAP Developers") no longer contains any sources (except those for the actual platform plug-ins) in order to reduce the size of the download package.

If you want to get the sources for plug-ins such as JDT which are not part of the core platform you have to retrieve them separately. To do so you can use the new plug-in import wizard which allows to fetch source projects corresponding to plug-ins of the target platform directly from the Eclipse CVS.

Just open the "Plug-ins" view, right-click on the plug-in you want to retrieve (e.g. org.eclipse.jdt.ui) and select "Import as" > "Project from a Repository ...". Confirm the next dialog by clicking "Finish", and the check-out starts. Afterwards the new project will automatically replace the plug-in JAR as dependency in any dependent projects within your workspace.

Saturday, July 24, 2010

Bookmark and Share

In the last couple of days I spent some time experimenting a little bit with CDI, the standard of the Java EE 6 platform for dependency injection services.

I must say that I really like that spec, as it hits the sweet spot between specifying features that provide a value out of the box (type-safe DI, eventing, interceptor services etc.) and being open enough to allow people to build totally new stuff based on it (using portable extensions).

I've got the feeling we're going to see a lot of exciting things based on CDI within the near future. Actually this reminds me a bit of Java annotations. Having been introduced with Java 5, just over time people started using them for more and more use cases that had not been foreseen in the first place.

Anyway, to do something practical with CDI I built a small portable extension which allows to retrieve JSR 223 scripting engines using dependency injection.

Just annotate any injection points of type javax.script.ScriptEngine with one of the qualifier annotations @Language, @Extension or @MimeType. The following code extract shows an example of a JavaScript engine (for example the Rhino engine shipping with Java 6) being injected into some managed bean, where it can be used for arbitrary script evaluations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestScoped
public class MyBean {

    @Inject 
    @Language("javascript") 
    private ScriptEngine jsEngine;

    // ...

    public void foo() throws ScriptException {

        assert 42.0d == (Double)jsEngine.eval("2 * 21");
        // ...
    }
}

The extension can be found in my Maven repository. Just add the following dependency to your POM in order to use it:

1
2
3
4
5
<dependency>
    <groupId>de.gmorling.cdi.extensions</groupId>
    <artifactId>scripting-extension</artifactId>
    <version>0.1</version>
</dependency>

In case you want to take a look at the source code (which is just a few lines), you can check it out from GitHub. As always, any ideas for improvement or other feedback are highly appreciated.