New DRY-er annotations for parameters

By Stephane Epardaud | May 29, 2018

You know DRY (Don't Repeat Yourself) and you wish every feature would be reviewed according to this criteria?

Good news everyone!

I've always found it annoying to repeat the name of the parameter variable in my JAX-RS resources:

 

@Path("param/{userId}")
public class ParamResource {
    
    @PathParam("userId")
    private String userId;
    
    @GET
    @Path("{orderId}")
    public String getOrder(@PathParam("orderId") String orderId) {
        return "User "+userId+" / Order "+orderId;
    }
}

 

I mean: surely with all the magic that JAX-RS does to help me, it could have figured out how to not make me duplicate, every single time, the parameter name I'm injecting? In JAX-RS there are six parameter types you can inject from the request: path, query, matrix, cookie, header and form (respectively @PathParam, @QueryParam, @MatrixParam, @CookieParam and @FormParam ). These annotations can be placed on fields, JavaBean property setters, or resource method parameters. Using Java reflection, it's pretty trivial to extract the field or JavaBean property name, but until Java 8, it has always been problematic to extract the resource method parameter name. This is probably why duplicating the parameter name in the annotation has always been required.

With Java 8, the Java compiler can actually record method parameter names in the bytecode. OK, ok, you can argue that we've always had those parameter names in the bytecode since the first Java release, because they're present in debugging symbols, which most people enable. But those debugging symbols are slightly annoying to get at because they require more than just reflection. In any case, with Java 8 it's become really trivial, so we decided to add new parameter annotations that would allow you to avoid specifying the name if it's the same as the variable you're annotating. Don't worry: if you want to have a different parameter name, you can always specify it (it's just optional). 

We've kept the annotation names the same, and of course, the JAX-RS annotations are still supported, but if you want, you can now import annotations from the org.jboss.resteasy.annotations.jaxrs package, and start removing all those duplicated parameter names from the annotations, leading to much DRY-er code like this:

import org.jboss.resteasy.annotations.jaxrs.*;

@Path("param/{userId}")
public class ParamResource {
    
    @PathParam
    private String userId;
    
    @GET
    @Path("{orderId}")
    public String getOrder(@PathParam String orderId) {
        return "User "+userId+" / Order "+orderId;
    }
}

Although this will work out of the box for fields and JavaBean property setters, if you want it to work for resource method parameters, don't forget to tell your Java compiler to add parameter names using one or more of the following methods:

  • Using javac: add the -parameters flag.
  • Using Maven: add the maven.compiler.parameters property:
<properties>
  <maven.compiler.parameters>true</maven.compiler.parameters>
</properties>
  • Using Eclipse: Go to Project > Properties > Java Compiler and select Store information about method parameters (usable via reflection).

  • Using IntelliJ IDEA: Go to Build, Execution, Deployment > Compiler > Java Compiler > Additional command line parameters and add the -parameters flag.

Note that you will need to use the 4.0.0-SNAPSHOT or 3.6.0-SNAPSHOT versions of RESTEasy to try this, because the feature hasn't been included in a release yet.

         

YourKit
YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications. YourKit is the creator of YourKit Java Profiler, YourKit .NET Profiler, and YourKit YouMonitor