Sunday, March 8, 2015

Comparing JSON Strings with Jackson

Here's a quick way to compare two JSON String using Jackson. While we could always do a simple String compare, this method allows us to keep the expected JSON in a readable format, such as pretty-printed in a test resource:

import com.fasterxml.jackson.databind.ObjectMapper

class JsonAssert {

    static ObjectMapper mapper = new ObjectMapper()

    static void areEqual(String json1, String json2) {
        def tree1 = mapper.readTree json1
        def tree2 = mapper.readTree json2

        assert tree1.equals(tree2)
    }

}

The above can be called from an expect: or then: block in a Spock specification.

Saturday, February 14, 2015

Simple Shell Script for Maven Integration Tests

Here's a simple shell script it took me forever to add to make it easier for me to run an integration test with Maven:

$ cat ~/bin/it
#!/bin/bash
mvn clean verify -Dit -Dit.test=$1
I just have to remember the test name now instead of repeatedly typing the above:
$ it MyIntegrationSpec

Sunday, November 30, 2014

Subversion: Recovering Password from Local Cache

Subversion: Recovering Password from Local Cache

If you've forgotten your Subversion password, you should be able to retrieve it from another machine where you've succesfully made a commit before.

If you look in the local cache for your server's authentication type, you should see a series a files with hexadecimal names.

For example, for a server using simple or basic authentication:

  $ ls ~/.subversion/auth/svn.simple
  2af94d688c4073220b0a6af1b5884861  887652dff29c33e3f09394ea7379fac9

If you then look in one of the file, you should see your password:

  $ cat ~/.subversion/auth/svn.simple/2af94d688c4073220b0a6af1b5884861 | grep -A 2 password
    password
    V 9
    mypassword

The above commands and locations are for a Linux box, but something similar should work on other OSes.

Wednesday, November 5, 2014

Spock and Objenesis: Resolving IllegalAccessError

Spock and Objenesis: Resolving IllegalAccessError

When mocking some classes with Spock in one of the usual ways, we often may need to include cglib. We also have to add objensis as well.

In one our modules, the latter was removed, leading to the below type of error that did not directly point out the cause:

java.lang.IllegalAccessError: tried to access method org.company.service.export.ExportRequest.<init>(Lorg/company/service/export/ExportRequest$Builder;)V from class org.company.service.export.ExportRequest$$EnhancerByCGLIB$$1969beb7
 at org.spockframework.mock.runtime.MockInstantiator.instantiate(MockInstantiator.java:33)
 at org.spockframework.mock.runtime.ProxyBasedMockFactory$CglibMockFactory.createMock(ProxyBasedMockFactory.java:92)
 at org.spockframework.mock.runtime.ProxyBasedMockFactory.create(ProxyBasedMockFactory.java:49)
 at org.spockframework.mock.runtime.JavaMockFactory.create(JavaMockFactory.java:51)
 at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:44)
 at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:47)
 at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:282)
 at org.spockframework.lang.SpecInternals.MockImpl(SpecInternals.java:83)
 at org.company.service.export.RecordExporterSpec.$spock_initializeFields(RecordExporterSpec.groovy:141)

For our mocking, we would define the mock at the field level like:

    ExportRequest request = Mock()

After adding objenesis, the error was resolved:

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.objenesis</groupId>
        <artifactId>objenesis</artifactId>
        <version>1.2</version>
    </dependency>

Saturday, November 1, 2014

Sending Email with Spring

Sending Email with Spring

At work, we were using an in-house dependnecy to send text-based internal emails out the door of one our webapps for notifications. The solution worked will for us, but did more than just send emails. As a result, depending on it introduced a large dependency tree to our application.

Since the artifact simply appeared to be a wrapper around Spring, which we were using directly anyway, we thought it might be better to write our own little solution instead, and simplify our application's dependency graph.

Below I'll describe some "highlights". A full project example can be found here: spring-mail-example

In our business processes, we send notifications to same email address and from the same sender. The only thing that may change is the subject of the email (success vs. failure) and the contents of the email. So we wanted a simple interface that just took both these parameters:

interface Sender {
    void send(String subject, String text)
}

Below is an implementation of the interface that:

  • Sends a simple MimeMessage with type text/html.
  • Expects the sender and recipient email address to be injected.
  • Expects the name and port of the mail host to use to be injected.
  • Creates an instance of JavaMailSender to help simplify configuration for the user.

The code:

class EmailSender implements Sender, InitializingBean {

    String mailHost
    int mailPort
    String fromAddress
    String toAddress

    protected JavaMailSender mailSender

    @Override
    void send(String subject, String text) {
        try {
            mailSender.send htmlMessageWith(subject, text)
        }
        catch (e) {
            logFailure e
            throw new MessageException(e)
        }

        logSent toAddress, subject, text
    }

    private MimeMessage htmlMessageWith(subject, text) {
        def mimeMessage = new MimeMessage(null)
        def messageHelper = new MimeMessageHelper(mimeMessage)

        messageHelper.with {
            addTo toAddress
            setFrom fromAddress
            setSubject subject
            setText text, true
        }

        messageHelper.mimeMessage
    }

    @Override
    void afterPropertiesSet() throws Exception {
        mailSender = new JavaMailSenderImpl()
        mailSender.setHost mailHost
        mailSender.setPort mailPort
    }
}

An example of how to configure the implementation with Spring:

    <bean class="prystasj.spring.mail.EmailSender">
       <property name="fromAddress" value="prystasj@company.org"/>
       <property name="toAddress" value="friend@company.org"/>
       <property name="mailHost" value="mailhost.company.org"/>
       <property name="mailPort" value="25"/>
   </bean>

In the end, we decided to go with this solution for our emails. While we now have code of our own to maintain, the resulting dependency tree is smaller, and we have control over adding any features we want, so for now the trade-off is worth it.

Sunday, September 21, 2014

Groovy: Import Aliases

A feature I like in Groovy is the ability to import class with aliases. I had forgotten about this feature, so I'm writing about it here to help get it to stick with me a bit.

Take this Spock test class tha has to define a couple several values of a couple types:

    import org.company.id.CorporateSymbol
    import org.company.id.CorporateName

    class CorporationMapperSpec extends Specification {

        @Subject
        CorporationMapper mapper = new CorporationMapper()

        def 'maps corporate symbols to names'() {
            expect:
            symbolsToNames == mapper.map(symbols)
        }

        def symbol1 = new CorporateSymbol('KRA')
        def symbol2 = new CorporateSymbol('VLY'),
        def symbll3 = new CorporateSymbol('KRS'),

        def symbolsToNames = [
            (symbol1): new CorporateName('Kramerica')
            (symbol2): new CorporateName('Vandalay')
            (symbol3): new CorporateName('Kruger')
        }
    }

We can use aliases with the import statements to make the code easier to work with:

    import org.company.id.CorporateSymbol as CS
    import org.company.id.CorporateName as CN

    class CorporationMapperSpec extends Specification {

        @Subject
        CorporationMapper mapper = new CorporationMapper()

        def 'maps corporate symbols to names'() {
            expect:
            symbolsToNames == mapper.map(symbols)
        }

        def symbol1 = new CS('KRA')
        def symbol2 = new CS('VLY'),
        def symbll3 = new CS('KRS'),

        def symbolsToNames = [
            (symbol1): new CN('Kramerica')
            (symbol2): new CN('Vandalay')
            (symbol3): new CN('Kruger')
        }
    }

I would be a little wary about using it in main source, as it does add a little bit of indirection to the readability of the code, but for test source, I think it can definitely help making the code easier to read and work with.

Sunday, September 7, 2014

Jackrabbit and XPath Queries: Escaping Paths

Jackrabbit and XPath Queries: Escaping Paths

We have a service that manages a Apache Jackrabbit repository. The main client of the service builds lists of records of the form: ///, where user's are represented by a UUID. For example:

  /JCP/feeadeaf-1dae-427f-bf4e-842b07965a93/label/

Now we started to build a web endpoint to the service that can be used to view the contents of the repository at any time. This endpoint may want to create a query into the repository along the lines of "show me all lists for institution JCP and user feeadeaf-1dae-427f-bf4e-842b07965a93". When we create lists in the repository, we increment a property named sequence (more on this on a later date), so an XPath query that proved to work for us given the above example proved to be:

  /*/JCP/feeadeaf-1dae-427f-bf4e-842b07965a93/label//*[@sequence]

This was working well at first until we started to execute queries where the UUID had a leading digit. We would see an exception in our logs of the form:

  Encountered "-" at line 1, column 26.
  Was expecting one of:
   ...
   ...
   ...
   ...
  ...
     for statement: for $v in /*/JCP/2eeadeaf-1dae-427f-bf4e-842b07965a93/label//*[@sequence] return $v

Since the hypen was indicated as the culprit by the exception message, and given the fact we only ran into this when the UUID node began with a digit, we thought that both conditions were required to create the invalid query. Our first attempt at a solution simply invovled prefixing all nodes that fit the pattern of a UUID with a string like uuid_.

In reality, it was simply the leading digit that caused the problem. The above solution would definitely not work for all future use cases of the service. The problem can simply be stated that the query was invalid as XML nodes cannot start with digits. We could still however create paths into the repository in the above manner as long as we escaped the leading digit in the query:

  /*/JCP/_x0032_eeadeaf-1dae-427f-bf4e-842b07965a93//*[@sequence]

The code below demonstrates our modeling of a path into the repository and the method by which we perform the escaping. Before that though it is worth noting that we had to encode the individual steps when building the path included in the query. If we included the whole path in the escaping logic, the delimiting slashes would be escaped, and the query would not work. If we included the query as a whole into the escaping logic, the asterisks would be escaped, and the query would not also work.

    import org.apache.commons.lang3.StringUtils;
    import org.apache.jackrabbit.util.ISO9075;

    class Path {
        List<String> steps; //...

        public String asQuery() {
            return steps.size() > 0 ? "/*" + asPathString(encodedSteps()) + "//*" : "//*";
        }

        private String asPathString(List<String> steps) {
            return '/' + StringUtils.join(steps, '/');
        }

        private List<String> encodedSteps() {
            List<String> encodedSteps = new ArrayList<>();
            for (String step : steps) {
                encodedSteps.add(ISO9075.encode(step));
            }
            return encodedSteps;
        }
    }

The ISO9075 class can be found in org.apache.jackrabbit:jackrabbit-jcr-commons.

My initial search for answers started on Stack Overflow, and of course the good folks answering questions there didn't let me down!