Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

The Maven Checkstyle Plugin is very useful to identity source files that do not follow your source coding standards. We chose to follow what Google used for their Checkstyle as the basis for ours. We made small tweaks to their standard, but those are contained within the declared file. Please note that Google used a new rule that wasn’t contained within the libraries that were included by the version of the maven-checkstyle-plugin that was available. To enable this additional functionality, we explicitly declared the version of the puppycrawl checkstyle dependency to use.

I configured the plugin to generate reports and to not fail on error, but to give warnings instead.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.17</version>
    <dependencies>
        <!--
        http://mvnrepository.com/artifact/com.puppycrawl.tools/checkstyle
        Needed because Google uses a new checkstyle that isn't included by the regular plugin.
        https://groups.google.com/forum/#!topic/checkstyle/OXux8RqJuXg
        -->
        <dependency>
            <groupId>com.puppycrawl.tools</groupId>
            <artifactId>checkstyle</artifactId>
            <version>6.19</version>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <goals>
                <goal>checkstyle</goal>
            </goals>
            <phase>verify</phase>
        </execution>
    </executions>
    <configuration>
        <configLocation>twinspires_checkstyle.xml</configLocation>
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <failOnViolation>false</failOnViolation>
        <linkXRef>false</linkXRef>
        <enableRulesSummary>true</enableRulesSummary>
        <enableSeveritySummary>true</enableSeveritySummary>
        <enableFilesSummary>true</enableFilesSummary>
        <includeTestSourceDirectory>true</includeTestSourceDirectory>
    </configuration>
</plugin>
<plugin>

The output of the plugin will contain the name of the Java class, the line number and a brief description of what the warning is, along with the checkstyle caregory. Example output is below:

[INFO] --- maven-checkstyle-plugin:2.17:checkstyle (default) @ newcam-server ---
[INFO] Starting audit...
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:10: Using the '.*' form of import should be avoided - com.twinspires.cam.entity.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:58: Using the '.*' form of import should be avoided - com.twinspires.cam.response.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:82: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:98: Abbreviation in name 'registerWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:125: Abbreviation in name 'updateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:177: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:194: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:350:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:363:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:517:9: '}' at column 9 should be on the same line as the next part of a multi-block statement (one that directly contains multiple blocks: if/else-if/else or try/catch/finally). [RightCurly]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:533:20: Method name 'eCommerceCustomerPreUpdateCheck' must match pattern '^[a-z][a-z0-9][a-zA-Z0-9_]*$'. [MethodName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:538: Abbreviation in name 'emailDTO' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:554: Abbreviation in name 'dtoCountryByISOCode' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:755:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:801: Distance between variable 'failReason' declaration and its first usage is 7, but allowed 3.  Consider to make that variable as final if you still need to store its value in advance (before method calls that might do side effect on original value). [VariableDeclarationUsageDistance]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:940: Abbreviation in name 'setRegisterWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:941: Abbreviation in name 'registerWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1155: Abbreviation in name 'setUpdateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1155: Abbreviation in name 'updateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1257: Line is longer than 120 characters (found 129). [LineLength]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/ICustomerServicesManager.java:47: Using the '.*' form of import should be avoided - com.twinspires.cam.response.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/ICustomerServicesManager.java:52: Abbreviation in name 'verifySSN' must contain no more than '1' capital letters. [AbbreviationAsWordInName]

October 19th, 2016

Posted In: java ninja, Javaninja, Maven

Leave a Comment

The Maven Dependency Plugin can give you dependency related information for your Maven projects. I use it for two main purposes

  • Dependencies that I declare, but do NOT use
  • Dependencies that I do NOT care, but do use

The minimal configuration is as follows:

            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>analyze</id>
                        <goals>
                            <goal>analyze-only</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

The normal behavior is to break the build when there is a problem. I was working on a pre-existing project and we were going to have to work through the problems over time, so this was counter-productive. To disable this behavior, I set the plugin to to fail on warnings. Another thing that I do is enable the output of XML for any used, but undeclared dependencies. This makes it very easy to copy/paste the missing dependencies.

            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>analyze</id>
                        <goals>
                            <goal>analyze-only</goal>
                        </goals>
                        <configuration>
                            <failOnWarning>false</failOnWarning>
                            <outputXML>true</outputXML>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

This is what sample output will look like. There are three different sections.

  • Used, but undeclared dependencies. These should be added to your POM file. You can copy the XML elements in the last section to easily add these.
  • Unused, but declared dependencies. These can usually be removed from your POM files. Please be aware that some dependencies are not explicitly declared and are determined at run-time (e.g Spring has multiple implementations for various functions).
  • The XML for the used, but undeclared dependencies. These XML snippets should be added to your POM files. This prevents your project from breaking when a dependency library changes its dependencies and inadvertantly breaks your build.
[INFO] --- maven-dependency-plugin:2.10:analyze-only (analyze) @ newcam-server ---
[WARNING] Used undeclared dependencies found:
[WARNING]    com.google.code.gson:gson:jar:2.5:compile
[WARNING] Unused declared dependencies found:
[WARNING]    com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.7.0:compile
[WARNING]    org.hibernate:hibernate-validator:jar:4.1.0.Final:compile
[WARNING]    mysql:mysql-connector-java:jar:5.1.34:provided
[WARNING]    org.hibernate:hibernate-entitymanager:jar:4.3.11.Final:compile
[WARNING]    org.slf4j:jcl-over-slf4j:jar:1.7.13:compile
[WARNING]    org.springframework:spring-orm:jar:4.2.4.RELEASE:compile
[WARNING]    org.slf4j:log4j-over-slf4j:jar:1.7.13:compile
[WARNING]    org.apache.commons:commons-dbcp2:jar:2.1:test
[WARNING]    org.apache.cxf:cxf-rt-frontend-jaxrs:jar:3.1.4:compile
[WARNING]    ch.qos.logback:logback-classic:jar:1.1.3:compile
[WARNING]    org.codehaus.jackson:jackson-xc:jar:1.9.13:compile
[INFO] Add the following to your pom to correct the missing dependencies: 
[INFO] 
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.5</version>
</dependency>
[INFO] 

October 19th, 2016

Posted In: java ninja, Javaninja, Maven

Leave a Comment

We had an interceptor that was written for Hibernate 3. When we went to Hibernate 4, we discovered that methods that we were used to using didn’t exist anymore. The original Hibernate 3 code looked like:

Session session = null;
MySQLMatchingRowCountInterceptor interceptor = new MySQLMatchingRowCountInterceptor();
session = ((Session) getROEntityManager().getDelegate()).getSessionFactory().openSession(interceptor);
session.beginTransaction();
interceptor.initialize(session);

Unfortunately, SessionFactory.openSession() no longer takes an interceptor.

To define an interceptor, you need to create the Session from the SessionFactory with the .withOptions() method. Once you do that, you can specify the interceptors.

Session session = null;
MySQLMatchingRowCountInterceptor interceptor = new MySQLMatchingRowCountInterceptor();
session = ((Session) getROEntityManager().getDelegate()).getSessionFactory()
                                                        .withOptions()
                                                        .interceptor(interceptor)
                                                        .openSession();
session.beginTransaction();
interceptor.initialize(session);

The Maven dependency we were using for Hibernate 4.3.11 is:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
</dependency>

October 11th, 2016

Posted In: hibernate, Java, java ninja, Javaninja

Leave a Comment

The Problem

We had a service written in Java that retrieved a number from the database and returned it through a RESTful service to a Javascript client. The number was a long because of it’s large size. This had worked for a very long time. However, we noticed that when we had some very large numbers, the number started to be off by one. Specifically,

9164083756384584
9597642508289680

Those values were displayed as

9164083756384585
9597642508289681

In Java, we are used to overflow behavior being represented by a number turning negative because the signed bit is being used to represent data.

The Findings

We were able to verify that when we called the service with Postman, that we did see the correct value. The problem occurred when the Javascript client tried to parse the data. There was a specific line where the value was taken from the json to string marshalled object and it was converted to a string. This is where the problem was. After much searching and consulting with our Javascript experts, we ended up with ECMA 8.5 The Number Type. What an eye opener. This confirmed to us that the largest number that we could expect to be retrieved from our Java RESTful services was 2^53-1, not 2^63-1.

We had no idea that 9007199254740991 was the largest value that we could expect to be represented accurately in Javascript.

The Solution

Our solution was to add a property to the object that we were returning for marshalling by our Java RESTful services. We updated the service to have an additional property that was a String. Meaning that we would transition to return a String as our record IDs, instead of a long. This was fine, since arithmetic operations shouldn’t be performed on our object IDs anyway.

More Findings

We also found supporting information at

  • http://stackoverflow.com/questions/307179/what-is-javascripts-highest-integer-value-that-a-number-can-go-to-without-losin
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE

October 4th, 2016

Posted In: ECMA, ECMAscript, Java, java ninja, Javaninja, javascript

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com