Author Archives: Joachim

Get detailed timings when running maven

When a maven build is slow, it is hard to figure out what is causing this and whether you can “fix” it by tweaking your build. With recent builds of maven, there is a good solution, use the maven buildtime extension.

The use is pretty simple, add a .mvn/extensions.xml file with following content

<?xml version="1.0" encoding="UTF-8"?>
<extensions>
    <extension>
        <groupId>co.leantechniques</groupId>
        <artifactId>maven-buildtime-extension</artifactId>
        <version>3.0.0</version>
    </extension>
</extensions>

The run your build with the “-Dbuildtime.output.log=true” parameter, e.g.

mvn clean install -Dbuildtime.output.log=true

You will now get a summary of timings for each build step just before mavens own summary.

Working with meta-annotations

Spring framework has the very nice feature of supporting meta-annotations. I wanted to implement the same thing for jTransfo.

The idea is that you can write a custom annotation to replace one or more other annotations. For example in jTransfo, you can define a @ReadOnly annotation which replaces @MappedBy(readOnly = true).

You can define the custom annotation like this:

@MappedBy(readOnly = true)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
public @interface ReadOnly {
 
}

Note that this annotation can itself also be used as meta-annotation thanks to the ANNOTATION_TYPE target.

To check whether an annotation exists on a field or method, you need to read through the chain. This can be done using this code:

    /**
     * Get the annotations of given type which are available on the annotated element. Considers both the annotations
     * on the element and the meta-annotations (annotations on the annotations).
     * The result is given in no specific order
     *
     * @param element annotated element
     * @param annotation annotation to find
     * @param <T> annotation type
     * @return
     */
    public <T extends Annotation> List<T> getAnnotationWithMeta(AnnotatedElement element, Class<T> annotation) {
        return (List) Stream.of(element.getDeclaredAnnotations())
                .flatMap(this::addMetaAnnotations)
                .filter(a -> annotation.isAssignableFrom(a.annotationType()))
                .collect(Collectors.toList());
    }
 
    private Stream<Annotation> addMetaAnnotations(Annotation a) {
        Set<Annotation> res = new HashSet<>();
        addMetaAnnotations(res, a);
        return res.stream();
    }
 
    private void addMetaAnnotations(Set<Annotation> set, Annotation annotation) {
        if (set.add(annotation)) { // set is needed or continues infinitely
            for (Annotation meta : annotation.annotationType().getDeclaredAnnotations()) {
                addMetaAnnotations(set, meta);
            }
        }
    }