Category: Uncategorized

RESTEasy Swagger Maven Cheat Sheet

dragonFly3

Settings.xml file

  • <deploy.env> This parameter is used for many things that have nothing to do with the RESTful API, but it also plays a role in the RESTful API.  It is used to create the URLs that allow us to access Swagger for the documentation and testing of the API.

In the pom.xml file, in the generate-service-docs execution, the additional parameters docBasePath and apiBasePath rely on both the resteasy.service.host and deploy.env parameters to construct URLs used by Swagger.

RESTeasy entries in web.xml file

https://docs.jboss.org/resteasy/docs/1.0.1.GA/userguide/html/Installation_Configuration.html

<listener>

This entry identifies the RESTeasy class that will initialize RESTeasy.

<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>

<servlet>

This entry identifies our class that extends the javax.ws.rs.Application class.  The RestApp identifies the RESTful beans, and some other classes that are used in packaging REST responses, formatting JSON, etc.

<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ep.ff.web.endpoint.RestApp</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>

 

<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<context-param>

Various parameters that control aspects of RESTeasy.  For each the parameter name and value are specified.

<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>

<context-param>
<param-name>resteasy.jndi.resources</param-name>
<param-value>earname/beanname/local
</param-value>
</context-param>

<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>

<security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>REST Resources</web-resource-name>
<url-pattern>/swagger/*</url-pattern>
<url-pattern>/apidocs/*</url-pattern>
<url-pattern>/rest/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>

<auth-constraint>
<role-name>rolename</role-name>
</auth-constraint>
</security-constraint>

RESTeasy entries in pom files

web

<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.7.Final</version>
</dependency>

<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>3.0.7.Final</version>
</dependency>

web-ejb

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>generate-service-docs</id>
<phase>generate-resources</phase>
<configuration>
<doclet>com.carma.swagger.doclet.ServiceDoclet</doclet>
<docletArtifact>
<groupId>com.carma</groupId>
<artifactId>swagger-doclet</artifactId>
<version>1.0.4.1</version>
</docletArtifact>
<reportOutputDirectory>output directory</reportOutputDirectory>
<useStandardDocletOptions>false</useStandardDocletOptions>
<additionalparam>-apiVersion 1 -docBasePath path/apidocs -apiBasePath path/rest</additionalparam>
</configuration>
<goals>
<goal>javadoc</goal>
</goals>
</execution>
</executions>
</plugin>

The -apiBasePath is used to resolve the URLs to the services for testing the methods via Swagger.  If the {resteasy.service.host} parameter is not supplied, either in the settings.xml file or on the maven command line, you will not be able to click into the links in Swagger to be able to see the documented API or test the services.

Steps to RESTful-ize an existing bean

  • WEB-INF\web.xml needs the web bean added to the resteasy.jndi.resources <context-param> tag in the <param-value> tag.  Follow the same pattern as the existing web beans. Comma delimit.
  • In RestApp.java, add the web bean in the setClasses() method.
  • In the web bean class itself, fix the @EJB annotations to include the name argument.
  • In the web interface class, add class-level and method-level REST annotations.
    • @GET, @POST, @DELETE, @PUT (usually @GET or @POST)
    • @Path(path name).  Take the method name, and change it to be all lower-case, hyphenated, and use that for the path name.
    • @Produces(MediaType.APPLICATION_JSON), @Consumes(MediaType.APPLICATION-JSON)
  • If the method does not have a @RolesAllowed tag, it must be added and tested.  Otherwise anyone will be able to access the method just by knowing the URL.
  • Handle cyclic references with a @JsonIgnore tag, to prevent StackOverflowError.

 

Swagger

Swagger is a tool that helps to document and test a RESTful API.

https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-RESTEasy-2.X-Project-Setup-1.5

Java Classes

RestApp

CustomJacksonJsonProvider

Allows for customization of the methods used to read and write JSON strings.

JsonMappingExceptionMapper

Creates an exception for errors related to Json mapping.

RestResponseInterceptor

Not feelin’ the regex love

thehemorrhoid Sometimes I come to a regular expression in code that someone else wrote (and they probably just ripped it off from stackoverflow or some such place and never bothered to understand exactly how it worked), and there are no comments explaining what this regex is intended to do.  Infuriating.  It not only counts on the developer down the road to know regular expressions well enough to figure out what it is supposed to be doing, but it also requires a bit of cross-temporal mind-meld to figure out what the problem was that the original developer was trying to solve.  Inevitably there will be some case that comes up and the particular regex they selected doesn’t handle it well.  It needs to be tweaked, so now you have to go about understanding the whole thing and the original developer left you no clues.

References:

Regex use versus abuse

CamelCase to Human Readable String

What to do?

Your decision about whether to figure it all out or just write some code that does the same thing may well depend upon how near your deadline is looming.

Faced with such a situation recently, with absolutely no time at all to handle this stupid little cosmetic bug, I opted for the just-write-the-damn-code option.

CamelCase to English in Actionscript

I just had to turn a camelCase string (I like to write camelCase in camelCase), into something more beautiful that you could display to a user.  The existing regex worked pretty well, except it fell down when an acronym was involved – too many capital letters in a row.  So you had a string LOLCatsAreFunny, and it ended up LOLCats Are Funny.  I needed that space between LOL and Cats.

Found a good place to start by 1.21 Gigawats at stackoverflow.  That solution didn’t have the tweak I needed, so here is the modified solution.  The tweak is in pink.

public static function prettifyCamelCase(value:String=""):String 
{ 
var output:String = ""; 
var len:int = value.length; 
var nextChar:String = ""; 

for (var i:int; i < len; i++) 
{ 
    char = value.charAt(i); 
    if (i < len - 1) 
    { 
        nextChar = value.charAt(i + 1); 
    } 

    if (i==0)
    { 
        output += char.toUpperCase(); 
    } 
    else if (char !== char.toLowerCase() && char === char.toUpperCase()
        && nextChar === nextChar.toLowerCase() 
        && nextChar !== nextChar.toUpperCase()) 
    {
        output += " " + char;
    } 
    else if (char == "-" || char == "_")
    {
        output += " ";
    } 
    else 
    { 
        output += char; 
    }
} 
return output; 
}

 

 

Duplicates in two columns in a table

thor-in-the-poppies-lisa-twede

That’s a painting of my cat Thor in the backyard.  Apparently he’s looking at the hose, despite the fact that to his right the yard is full of California Poppies.

Today’s blog has some code that is not my own.  Michael Powaga posted it over on Stack Overflow.  I just wanted to keep track of this little gem because I’ve needed it twice now and both times I ended up going with his solution.

I needed to know how many rows (and which ones) were duplicates but not just on one column, on two columns.  I had a situation where (I feel) there should have been a constraint to prevent duplicates in this table.  I wanted to neatly identify the offending records so I could deal with them.

This is his code.  It’s at the link above, but also copied here just in case.

select s.id, t.* 
from [stuff] s
join (
    select name, city, count(*) as qty
    from [stuff]
    group by name, city
    having count(*) > 1
) t on s.name = t.name and s.city = t.city

XML Parser

barn-owl-landing-lisa-twede

References:

Needed to parse an XML import file in a Java application.  I liked what I read about JAXB here, so this is the XML parser I used.  What I liked about it is that I didn’t need to write code to deal with the XML file line-by-line.  With JAXB, you do a little prep work to create a schema for the XML file, and at run-time the JAXB methods just need to know the location of the XML file and the location of the class definitions and it creates your Java objects.  Then you just deal with these objects in your Java code however you please. Not a lot of fuss involved.

Creating the schema

First step is to create a schema from your XML file.  I used a free online schema generator.  I just uploaded my XML file and it created an XSD schema for me.

Creating classes (called binding the schema)

The Java SDK comes with a tool for this.  You don’t need to download or install anything that you don’t already have.  The tool is xjc, and it’s in Java’s bin folder.  You can type xjc -help to learn about all the options.  But the main syntax you need is this:

xjc -d <directory to create Java class files in> -p <package name to use in the class files> <schema created in previous step with a .xsd file extension>

Java code

You need these imports:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;

The code:

 JAXBContext jaxbContext = JAXBContext.newInstance(location of classes you created using the xjc tool);
 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
 Object o = unmarshaller.unmarshal(new File(location and name of XML file to parse));

You can cast the output to the object type immediately if you’re only using this code for one type of XML file and you know what type of object it will always generate.  Or leave it as an Object if you want this to handle any XML file, and then later check the type of object with instanceof .