Friday, October 4, 2013

Java: Reflecting to Get All Classes in a Package, check and invoke method dynamically

It took me a little while to figure out that Java doesn't provide a way to reflect an entire package. In other words, there is no built-in way for me to dynamically retrieve a list of all the classes in a given package in Java through reflection. So I wrote my own method to do it.
Since it took a bit of googling and effort, I thought it would be nice to share the convenience method I wrote with the world. Enjoy:

Main.java under code.com.pritom package

package code.com.pritom;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;

public class Main {
    java.lang.reflect.Method method;

    public static void main(String[] args) throws Exception{
        Main main = new Main();
    }

    public Main() throws Exception{
        Class loadClass = getClassObjectByName("Load");
        System.out.println("Product Type Class: " + loadClass);
        System.out.println("Product Type Simple Name: " + loadClass.getSimpleName());
        System.out.println("Product Type Package Name: " + loadClass.getPackage().getName());
        System.out.println("Product Type Is Enum: " + loadClass.isEnum());

        try {
            method = loadClass.getMethod("println", String.class);
            System.out.println("Method Exists: println(String.class)");
            method.invoke(loadClass.newInstance(), "Pritom");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            Class[] classes = new Class[2];
            classes[0] = String.class;
            classes[1] = Integer.class;
            method = loadClass.getMethod("println", classes);
            System.out.println("Method Exists: println(String.class, Integer.class)");
            method.invoke(loadClass.newInstance(), "Pritom", 26);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    private static HashMap allClassList = new HashMap();
    private static HashMap classObjectList = new HashMap();
    private static HashMap allClassObjectList = new HashMap();

    public static Class getClassObjectByName(String name) throws Exception {
        if(allClassObjectList.containsKey(name)) {
            return (Class) allClassObjectList.get(name);
        }
        String packageName = "code.com.pritom";
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        Enumeration<URL> resources = classLoader.getResources(path);
        List<File> dirs = new ArrayList<File>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        ArrayList<String> classes = new ArrayList<String>();
        for (File directory : dirs) {
            findClasses(directory, packageName);
        }
        if(allClassList.containsKey(name)) {
            Object object = getClassObjectByFullName(allClassList.get(name).toString()); /* Get the object */
            allClassObjectList.put(name, object); /* Storing for further use by class name only */
            return (Class) object; /* Return object */
        }
        throw new Exception("Invalid entity '" + name + "'");
    }

    private static void findClasses(File directory, String packageName) throws ClassNotFoundException {
        if (!directory.exists()) {
            return;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                findClasses(file, packageName + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                allClassList.put(file.getName().substring(0, file.getName().length() - 6), packageName + "." + file.getName().substring(0, file.getName().length() - 6));
            }
        }
    }

    private static Object getClassObjectByFullName(String fullName) throws Exception {
        if (classObjectList.containsKey(fullName)) {
            return classObjectList.get(fullName);
        }
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Object object = Class.forName(fullName, true, classLoader);
            classObjectList.put(fullName, object); /* Storing by (package + class) name */
            return object;
        } catch (Exception ex) {
            throw new Exception(fullName + " does not appear to be a valid class.");
        }
    }
}

And Load.java under code.com.pritom package


package code.com.pritom;

public class Load {
    public void println(String text) {
        System.out.println("\tName: " + text);
    }
    public void println(String text, Integer age) {
        System.out.println("\tName: " + text +", Age: " + age);
    }
}


And output will be as follows:


Product Type Class: class code.com.pritom.Load
Product Type Simple Name: Load
Product Type Package Name: code.com.pritom
Product Type Is Enum: false
Method Exists: println(String.class)
	Name: Pritom
Method Exists: println(String.class, Integer.class)
	Name: Pritom, Age: 26

Thursday, October 3, 2013

Grails Groovy dynamically invokeMethod with empty/single/multi parameters

You need to first get bean object of your service class.
Create a service like below and get your required service by calling:


serviceFinderService.getServiceByName("serviceName");

 If you have a service named "StudentService.groovy" then replace "serviceName" with "Student" or "student".


package com.pritom.services

import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes

class ServiceFinderService {
    private static HashMap beanList = new HashMap();
    private def grailsApplication;
    private static def ctx;

    def serviceMethod() {

    }

    public def getServiceByName(String bean) throws Exception {
        if(!ctx) {
            ctx = ServletContextHolder.servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
        }
        bean += "Service";
        bean = bean[0].toLowerCase() + bean.substring(1);
        if(beanList.containsKey(bean)) {
            return beanList.get(bean);
        }
        beanList.put(bean, ctx.getBean(bean));
        if(beanList.containsKey(bean)) {
            return beanList.get(bean);
        }
        throw new Exception("Invalid service");
    }
}


Now check and invoke the method if a specific method existing by such way:


def studentService = ServiceFinderService.getServiceByName("Student");

if(studentService.metaClass.respondsTo(studentService, "methodName", [Integer, String, Boolean] as Object[]) {
    def result = studentService.invokeMethod("methodName", [1, "Pritom K Mondal", true] as Object[]);
}

/* If your method is static then call it by: */
if(studentService.metaClass.respondsTo(studentService, "methodName", [Integer, String, Boolean] as Object[]) {
    def result = studentService.metaClass.getTheClass().invokeMethod("methodName", [1, "Pritom K Mondal", true] as Object[]);
}


Wednesday, October 2, 2013

Grails validate email address

you can use

import org.apache.commons.validator.EmailValidator
...
EmailValidator emailValidator = EmailValidator.getInstance()
if (emailValidator.isValid(valueToTest)) ....

the apache commons validators are included with Grails so you don't need to install another plugin.

Grails Hibernate - null id in entry (don't flush the Session after an exception occurs)

I ran into this issue today when trying to persist one of my objects.  The cause of the problem was interesting.  I was trying to save an object when a property/columns in the table had a unique constraint.  As a result, the object that I was trying to persist would not persist simply because the object's property it failed to meet the unique constraint.

As a result, a call to Save() on the object failed and the ID on the object I was trying to save was not set, but Grails Hibernate still processed the object and associated it with its persistence mechanism leaving it in a "semi-persistent" state with the Grails Hibernate persistence manager (ie: Grails Hibernate now knows about the object you tried to save and it SHOULD have fully evicted the object from its persistence manager because the save failed, but it didn't).

So, the solution that I implemented was to wrap the Save() in a try{} catch{} statement and handling exception.

Basically you need to do something like this:
Create a Filters in conf directory under grails project suppose named 'BaseFilters.groovy' with the following content:
 
import org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.hibernate.FlushMode
import org.hibernate.Session
import org.hibernate.SessionFactory

class BaseFilters {
    private static GrailsWebApplicationContext ctx;

    def filters = {
        all(controller:'*', action:'*') {
            before = {
                Session session = getRequestSession();
                session.setFlushMode(FlushMode.MANUAL)
                request.requestSession = session;
            }
            after = { Map model ->
                try {
                    Session session = request.requestSession;
                    session.flush();
                } catch (Exception ex) {
                    ex.printStackTrace()
                }
            }
            afterView = { Exception e ->

            }
        }
    }

    private Session getRequestSession() {
        createCtx();
        SessionFactory sessionFactory = ctx.sessionFactory
        Session session = sessionFactory.currentSession
        return session;
    }

    private def createCtx() {
        if(!ctx) {
            ctx = ServletContextHolder.servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
        }
    }
}

Originally session flush mode initially set to 'FlushMode.AUTO' which cause the error.
So I change the session flush mode to 'FlushMode' to 'MANUAL'.
And also make your service transaction false such: static transactional = false, add this line just below the class definition.

And in the after section, I just manually try to flush, which is not much needed, you can ignore it.
I just add this section to do some logic manually if need.

Tuesday, October 1, 2013

Grails domain class: unique constraint for multiple columns

Suppose a simple Grails domain class:


class Account {
    String countryId;

    String userName; 
 
    String areaId;
 
    String password;

    static constraints = {
        ...???...
    }
}


It is required that user names are unique for a particular countryId and areaId, thus there must be a unique contraint on three columns. And this is the constraints:

userName(unique: ['countryId', 'areaId'])
 
You can include as many other properties in the array that make up the 
other properties that must be considered in the "unique" constraint on 
the username. 

Grails pagination on a ArrayList

In my recent grails project, i needed to paginate on an array list, so I wrote a function and thought would share it with you all.

public List getFilteredList(int max, int offset) {
    max = Math.min(max ?: 25, 100)
    offset = (offset && offset > 0) ?: 0

    List names = getNames() //Loads the complete list
    int total = names.size()
    int upperLimit = findUpperIndex(offset, max, total)
    List filteredNames = names.getAt(offset..upperLimit)
    return filteredNames
}

private static int findUpperIndex(int offset, int max, int total) {
    max = offset + max - 1
    if (max >= total) {
        max -= max - total + 1
    }
    return max
}
So now if offset=20 and max=10, total = 28 so this will generate a list from 21st to 28th elements of the main list.

Grails: get class object by string/class name

grailsApplication.classLoader.loadClass("au.com.test.package.ClassName")