Category Archives: Groovy

Groovy: Log Annotation

PROBLEM

My personal goal of 2017 is to write less useless-yet-neccessary code, such as initializing a logger:-

import org.slf4j.Logger
import org.slf4j.LoggerFactory

class MyClass {
    static Logger LOGGER = LoggerFactory.getLogger(MyClass)

    static void main(String[] args) {
        LOGGER.debug('TEST')
    }
}

SOLUTION

Groovy provides several useful annotations that allow us to inject a logger instance into the class.

Here’s a rewrite of the above example:-

import groovy.util.logging.Slf4j

@Slf4j
class MyClass {
    static void main(String[] args) {
        log.debug('TEST')
    }
}

If we insist of using the same variable ( LOGGER ), we can do this:-

import groovy.util.logging.Slf4j

@Slf4j(value = 'LOGGER')
class MyClass {
    static void main(String[] args) {
        LOGGER.debug('TEST')
    }
}

We can also use @Log for Java Util Logger, @Log4j for Log4j and @Commons for Apache Common Logging.

Advertisements

LdapTemplate: javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name ‘…’

BACKGROUND

Let’s assume we have the following LDAP configuration…

@Configuration
class LdapConfig {
    @Bean
    AuthenticationSource getAuthenticationSource(AppConfigService appConfigService) {
        return new AuthenticationSource() { ... }
    }

    @Bean
    ContextSource contextSource(AuthenticationSource authenticationSource) {
        return new LdapContextSource(
                authenticationSource: authenticationSource,
                url: 'ldap://server:389',
                base: 'dc=domain'
        )
    }

    @Bean
    LdapTemplate getLdapTemplate(ContextSource contextSource) {
        return new LdapTemplate(contextSource: contextSource)
    }
}

When running any LDAP query, the following exception is thrown:-

Caused by: javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name '/'
	at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2846)
	at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2820)
	at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129)
	at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198)
	at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171)
	at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:365)

SOLUTION

There are 3 solutions to this problem.

Query against Gobal Catalog

To prevent the referral issues when dealing with Active Directory, we may query against the Global Catalog by using port 3268.

@Bean
ContextSource contextSource(AuthenticationSource authenticationSource) {
    return new LdapContextSource(
            authenticationSource: authenticationSource,
            url: 'ldap://server:3268',
            base: 'dc=domain'
    )
}

The possible downside to this approach is the Global Catalog may not have the pertinent data we need, such as employeeID, etc.

Configure Referral to Follow

We can configure LdapTemplate to automatically follow any referrals.

@Bean
ContextSource contextSource(AuthenticationSource authenticationSource) {
    return new LdapContextSource(
            authenticationSource: authenticationSource,
            url: 'ldap://server:389',
            base: 'dc=domain',
            referral: 'follow'
    )
}

The downside to this approach is it makes the query much slower. Based on my testing, it is at least 5 to 10 seconds slower.

Ignore Exception

Sometimes, it pays to read the JavaDoc. Based on the LdapTemplate’s documentation, it says…

Note for Active Directory (AD) users: AD servers are apparently unable to handle referrals automatically, which causes a PartialResultException to be thrown whenever a referral is encountered in a search. To avoid this, set the ignorePartialResultException property to true. There is currently no way of manually handling these referrals in the form of ReferralException, i.e. either you get the exception (and your results are lost) or all referrals are ignored (if the server is unable to handle them properly. Neither is there any simple way to get notified that a PartialResultException has been ignored (other than in the log).

Bada Bing, Bada Boom…

@Bean
LdapTemplate getLdapTemplate(ContextSource contextSource) {
    return new LdapTemplate(
            contextSource: contextSource,
            ignorePartialResultException: true
    )
}

LdapTemplate: AttributesMapper vs ContextMapper

BACKGROUND

When using Spring’s LdapTemplate, there are two ways to transform the queried results: AttributesMapper and ContextMapper.

List<MyBean> list = ldapTemplate.search(
    '',
    '(cn=some-group-name)',
    // AttributesMapper or ContextMapper 
)

Here’s the comparison between these mapper classes.

AttributesMapper

If you are migrating your existing LDAP queries to Spring’s LdapTemplate, AttributesMapper seems ideal because you can copy most of the code over because it provides javax.naming.directory.Attributes.

List<MyBean> list = ldapTemplate.search(
    '',
    '(cn=some-group-name)',
    new AttributesMapper<MyBean>() {
        @Override
        MyBean mapFromAttributes(final Attributes attributes) throws NamingException {
            return new MyBean(
                cn: attributes.get('cn')?.get(),
                members: attributes.get('member')?.getAll()?.toSet() as Set<String> ?: []
            )
        }
    }
)

However, you have to handle possible null values if the attribute keys do not exist.

ContextMapper

With ContextMapper, it handles null values for us. Spring also provides an abstract class called AbstractContextMapper to further simplify the code.

List<MyBean> list = ldapTemplate.search(
    '',
    '(cn=some-group-name)',
    new AbstractContextMapper<MyBean>() {
        @Override
        protected MyBean doMapFromContext(final DirContextOperations ctx) {
            return new MyBean(
                cn: ctx.getStringAttribute('cn'),
                members: ctx.getStringAttributes('member')
            )
        }
    }
)

Spring: Component Scan Selected Classes

PROBLEM

Let’s assume we have a package with the following classes where each class is either annotated with Spring’s @Service, @Component, @Controller or @Repository.

app
├── A.groovy
├── B.groovy
├── C.groovy
├── D.groovy
└── E.groovy

When writing unit test, we want Spring to component scan class A and class B.

SOLUTION

Before we begin, we configure Log4j to log Spring in debug level.

<logger name="org.springframework">
    <level value="debug"/>
</logger>

Step 1

If we configure the test class like this…

@ContextConfiguration
class ASpec extends Specification {
    @Configuration
    @ComponentScan(
            basePackageClasses = [A]
	)
    static class TestConfig {
    }

    def "..."() {
        // ...
    }
}

It will scan all Spring components that reside in the same package as class A.

Debugging log:-

[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/A.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/B.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/C.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/D.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/E.class]

Step 2

We can set includeFilters to include just class A and class B…

@ContextConfiguration
class ASpec extends Specification {
    @Configuration
    @ComponentScan(
            basePackageClasses = [A],
            includeFilters = [@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = [A, B])]
	)
    static class TestConfig {
    }

    def "..."() {
        // ...
    }
}

… but it doesn’t do anything.

Debugging log:-

[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/A.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/B.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/C.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/D.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/E.class]

Step 3

To fix this, we set useDefaultFilters to false to disable any automatic detection of classes annotated with Spring’s @Service, @Component, @Controller or @Repository.

@ContextConfiguration
class ASpec extends Specification {
    @Configuration
    @ComponentScan(
            basePackageClasses = [A],
            useDefaultFilters = false,
            includeFilters = [@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = [A, B])]
    )
    static class TestConfig {
    }

    def "..."() {
        // ...
    }
}

Now, we get the intended behavior.

Debugging log:-

[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/A.class]
[DEBUG] [ClassPathBeanDefinitionScanner] [findCandidateComponents:294] - Identified candidate component class: file [/path/target/classes/app/B.class]

Guava: Testing equals(..) and hashcode(..)

PROBLEM

Let’s assume we want to test the following equals(..):-

public class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Person person = (Person) o;
        return Objects.equal(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

A correctly implemented equals(..) must be reflexive, symmetric, transitive, consistent and handles null comparison.

In another word, you have to write test cases to pass at least these 5 rules. Anything less is pure bullshit.

SOLUTION

You can write these tests yourself… or you can leverage Guava’s EqualsTester. This library will test these 5 rules and ensure the generated hashcode matches too.

First, include the needed dependency:-

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava-testlib</artifactId>
    <version>18.0</version>
    <scope>test</scope>
</dependency>

Instead of writing JUnit tests, I’ll be writing Spock specs, which is essentially built on top of Groovy, because it allows me to write very clear and clean tests.

class PersonSpec extends Specification {

    def person = new Person(name: 'Mike', age: 10)

    def "equals - equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Mike', age: 10),
                                 new Person(name: 'Mike', age: 20)).
                testEquals()

        then:
        notThrown(AssertionFailedError.class)
    }

    def "equals - not equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Kurt', age: 10)).
                testEquals()

        then:
        thrown(AssertionFailedError.class)
    }
}

Oh… wait for it… BOOM!

Java + Groovy: Creating Immutable List

Java: Mutable List

// class java.util.Arrays$ArrayList
final List mutableList = Arrays.asList(1, 2, 3);

Java: Immutable List

// class java.util.Collections$UnmodifiableRandomAccessList
final List immutableList = Collections.unmodifiableList(Arrays.asList(1, 2, 3));

Java: Immutable List using Guava

// class com.google.common.collect.RegularImmutableList
final ImmutableList guavaImmutableList = ImmutableList.of(1, 2, 3);

Groovy: Immutable List

// class java.util.Collections$UnmodifiableRandomAccessList
final def groovyImmutableList = [1, 2, 3].asImmutable()

Comparing Disassembled Java Class From JVM Languages

All JVM languages come with some degrees of syntactic sugar to make the code easier to read and write.

To satisfy my curiosity, I decided to run javap command to disassemble the bytecode inside the class file generated from several JVM languages. The chosen languages are Java, Groovy, Scala, JRuby and Rhino. I left out Clojure because the syntax does not compute for me after having my heavy lunch.

JAVA

Source Code

public class JavaPerson {
    private String name;
    private int age;

    public JavaPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Disassembled Java Class

public class com.choonchernlim.epicapp.JavaPerson {
  public com.choonchernlim.epicapp.JavaPerson(java.lang.String, int);
  public java.lang.String getName();
  public int getAge();
}

GROOVY

Source Code

class GroovyPerson {
    String name
    int age
}

Disassembled Java Class

public class com.choonchernlim.epicapp.GroovyPerson implements groovy.lang.GroovyObject {
  public static transient boolean __$stMC;
  public static long __timeStamp;
  public static long __timeStamp__239_neverHappen1395328777863;
  public com.choonchernlim.epicapp.GroovyPerson();
  public java.lang.Object this$dist$invoke$1(java.lang.String, java.lang.Object);
  public void this$dist$set$1(java.lang.String, java.lang.Object);
  public java.lang.Object this$dist$get$1(java.lang.String);
  protected groovy.lang.MetaClass $getStaticMetaClass();
  public groovy.lang.MetaClass getMetaClass();
  public void setMetaClass(groovy.lang.MetaClass);
  public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
  public java.lang.Object getProperty(java.lang.String);
  public void setProperty(java.lang.String, java.lang.Object);
  public static void __$swapInit();
  static {};
  public java.lang.String getName();
  public void setName(java.lang.String);
  public int getAge();
  public void setAge(int);
  public void super$1$wait();
  public java.lang.String super$1$toString();
  public void super$1$wait(long);
  public void super$1$wait(long, int);
  public void super$1$notify();
  public void super$1$notifyAll();
  public java.lang.Class super$1$getClass();
  public java.lang.Object super$1$clone();
  public boolean super$1$equals(java.lang.Object);
  public int super$1$hashCode();
  public void super$1$finalize();
  static java.lang.Class class$(java.lang.String);
}

SCALA

Source Code

class ScalaPerson(val name: String, val age: Int) {
}

Disassembled Java Class

public class ScalaPerson {
  public java.lang.String name();
  public int age();
  public ScalaPerson(java.lang.String, int);
}

JRUBY

Source Code

require 'java'

class JRubyPerson
  java_signature 'JRubyPerson(String, int)'
  def initialize (name, age)
    @name= name
    @age = age
  end

  java_signature 'String getName()'
  def name;
      @name
  end

  java_signature 'int getAge()'
  def age;
    @age
  end
end

Disassembled Java Class

public class JRubyPerson extends org.jruby.RubyObject {
  public static org.jruby.runtime.builtin.IRubyObject __allocate__(org.jruby.Ruby, org.jruby.RubyClass);
  public JRubyPerson(java.lang.String, int);
  public java.lang.String getName();
  public int getAge();
  static {};
}

RHINO

Source Code

function RhinoPerson( name, age ) {
    this.name = name;
    this.age = age;

    this.getName = function () {
        return this.name;
    };

    this.getAge = function () {
        return this.age;
    };
}

Disassembled Java Class

public class RhinoPerson extends org.mozilla.javascript.NativeFunction implements org.mozilla.javascript.Script {
  public RhinoPerson(org.mozilla.javascript.Scriptable, org.mozilla.javascript.Context, int);
  public RhinoPerson();
  public static void main(java.lang.String[]);
  public final java.lang.Object exec(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable);
  public final java.lang.Object call(org.mozilla.javascript.Context, org.mozilla.javascript.Scriptable, org.mozilla.javascript.Scriptable, java.lang.Object[]);
  public int getLanguageVersion();
  public java.lang.String getFunctionName();
  public int getParamCount();
  public int getParamAndVarCount();
  public java.lang.String getParamOrVarName(int);
  public java.lang.String getEncodedSource();
  public boolean getParamOrVarConst(int);
}