Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

I was going through some of the code and noticed how much Java code was being taken up to write normal equals(), hashCode() and toString() methods. There has to be a better way. Here is what I came up with.

This example was intended for an entity, but it doesn’t matter.

package com.cdi.igs.vip.dao;


import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;

/**
 * Base class for data access objects.
 * @author norris.shelton
 */
public class BaseEntity {

    /**
     * Indicates whether some other object is "equal to" this one.
     * <p>
     * The {@code equals} method implements an equivalence relation on non-null object references: <ul> <li>It is
     * <i>reflexive</i>: for any non-null reference value {@code x}, {@code x.equals(x)} should return {@code true}.
     * <li>It is <i>symmetric</i>: for any non-null reference values {@code x} and {@code y}, {@code x.equals(y)} should
     * return {@code true} if and only if {@code y.equals(x)} returns {@code true}. <li>It is <i>transitive</i>: for any
     * non-null reference values {@code x}, {@code y}, and {@code z}, if {@code x.equals(y)} returns {@code true} and
     * {@code y.equals(z)} returns {@code true}, then {@code x.equals(z)} should return {@code true}. <li>It is
     * <i>consistent</i>: for any non-null reference values {@code x} and {@code y}, multiple invocations of {@code
     * x.equals(y)} consistently return {@code true} or consistently return {@code false}, provided no information used
     * in {@code equals} comparisons on the objects is modified. <li>For any non-null reference value {@code x}, {@code
     * x.equals(null)} should return {@code false}. </ul>
     * <p>
     * The {@code equals} method for class {@code Object} implements the most discriminating possible equivalence
     * relation on objects; that is, for any non-null reference values {@code x} and {@code y}, this method returns
     * {@code true} if and only if {@code x} and {@code y} refer to the same object ({@code x == y} has the value {@code
     * true}).
     * <p>
     * Note that it is generally necessary to override the {@code hashCode} method whenever this method is overridden,
     * so as to maintain the general contract for the {@code hashCode} method, which states that equal objects must have
     * equal hash codes.
     * @param obj the reference object with which to compare.
     * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise.
     * @see #hashCode()
     * @see java.util.HashMap
     */
    @Override
    public boolean equals(Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

    /**
     * Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those
     * provided by {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is: <ul> <li>Whenever it is invoked on the same object more than once
     * during an execution of a Java application, the {@code hashCode} method must consistently return the same integer,
     * provided no information used in {@code equals} comparisons on the object is modified. This integer need not
     * remain consistent from one execution of an application to another execution of the same application. <li>If two
     * objects are equal according to the {@code equals(Object)} method, then calling the {@code hashCode} method on
     * each of the two objects must produce the same integer result. <li>It is <em>not</em> required that if two objects
     * are unequal according to the {@link Object#equals(Object)} method, then calling the {@code
     * hashCode} method on each of the two objects must produce distinct integer results.  However, the programmer
     * should be aware that producing distinct integer results for unequal objects may improve the performance of hash
     * tables. </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by class {@code Object} does return distinct
     * integers for distinct objects. (This is typically implemented by converting the internal address of the object
     * into an integer, but this implementation technique is not required by the Java&trade; programming language.)
     * @return a hash code value for this object.
     * @see Object#equals(Object)
     * @see System#identityHashCode
     */
    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    /**
     * Returns a string representation of the object. In general, the {@code toString} method returns a string that
     * "textually represents" this object. The result should be a concise but informative representation that is easy
     * for a person to read. It is recommended that all subclasses override this method.
     * <p>
     * The {@code toString} method for class {@code Object} returns a string consisting of the name of the class of
     * which the object is an instance, the at-sign character `{@code @}', and the unsigned hexadecimal representation
     * of the hash code of the object. In other words, this method returns a string equal to the value of: <blockquote>
     * <pre>
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * </pre></blockquote>
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
}

October 12th, 2015

Posted In: Java, java ninja, Javaninja, javascript

Tags: , , ,

Leave a Comment

Continuing from my Http Get Example, here is an example of an HttpClient4 String post example.

    /**
     * Performs HTTP post.
     * @param url http resource to post
     * @return string response
     */
    protected String post(String url) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String responseBody = null;
        try {
            responseBody = httpClient.execute(httpPost, responseHandler);
        } catch (IOException e) {
            log.error("IOException", e);
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpClient.getConnectionManager().shutdown();
        }
        return responseBody;
    }

December 11th, 2014

Posted In: Java

Tags: , , , , , , , ,

One Comment

This was an older piece of code that I had. Add the following dependency.

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.0.1</version>
        </dependency>

I made a wrapper method that performs a get of a given URL and returns a string.

    /**
     * Performs HTTP gets.
     * @param url http resource to get
     * @return string response
     */
    protected String get(String url) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String responseBody = null;
        try {
            responseBody = httpClient.execute(httpGet, responseHandler);
        } catch (IOException e) {
            log.error("IOException", e);
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpClient.getConnectionManager().shutdown();
        }
        return responseBody;
    }

December 10th, 2014

Posted In: Java

Tags: , , , ,

One Comment

Logging is needed, but all of the different frameworks makes this a pain. You are trying to research a problem and you have to bounce from log to log to research it.

SLF4J has bridge implementations that delegate to SLF4J APIs for commons-logging, log4j and even jdk logging.

You need to include the dependency for the logging API that you want to hijack as provided so they will not be packaged, then include the SLF4J bridge api. Repeat for each logging API you want to hijack, then include a SLF4J logging implementation, then away you go.

Here is how to hijack log4j

        <!--hijack log4j-->
        <!--NOTE Saying it is provided so it will not be packaged in my builds if a dependency is using it-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <version>${slf4j.version}</version>
            <scope>provided</scope>
        </dependency>

There are 3 strains of log4j (1.2, 1.3 & 2.0). None are compatible with any of the other. Luckily, only 1.2 is commonly used.

Here is how to hijack commons-logging

        <!--hijack commons logging-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

There is also a jcl104-over-slf4j for commons-logging 1.0.x. I tried to be slick and include that on a project and it got ugly. Those versions of the commons-logging API must not be compatible.

I usually don’t hijack the jdk logging because I rarely encounter it.

All that is remaining is to include a SLF4J implementation. There is one for commons-logging and log4j, but my preferred solution is logback.

        <!-- LogBack -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>0.9.27</version>
        </dependency>

This is what works for me, but I see where there could be problems. The logging APIs that I am hijacking are in the compile classpath, but not in the deploy classpath. It could be possible to use Maven exclusions to totally strip out the artifacts, but you must put an exclusion on each dependency that uses the artifact. Good luck keeping up with that. They are supposed to fix this in maven 3.1

February 3rd, 2011

Posted In: Java, logback, slf4j

Tags: , , , , , , , ,

Leave a Comment

WP to LinkedIn Auto Publish Powered By : XYZScripts.com