Wednesday, October 30, 2013

Transactions in Grails to roll back inconsistent data

The withTransaction function will participate in an existing transaction if one already has been started and would start a new one if not. The withNewTransaction method will always start a new transaction regardless of if one has already been started, isolating the code inside that block into it's own transaction (with it's own commit/rollback).

If you think the method you are developing should or could participate in some larger transaction with multiple separate db writes, then you should use withTransaction so that you can participate in a larger transaction if necessary. If you want your write here to be totally isolated from other db writes if another transaction is going on (and not potentially roll back that other transaction if this code fails), then use withNewTransaction.

In regards to your question two, these two will behave the same if they are the only calls being made in an action as they would both start up a new transaction.

def saveInstance = {
   /* Assume 'User' and 'Role' are two difference domain.
   Where Role is as a belongsTo of User.
   So need to first save Role and then User.
   But if Role saved and User not saved for any reason, then what happened???
   Role exists in database???
   For this we need to roll back data.
   Everything inside this block is run in a transaction as the name indicates. */
   User.withTransaction { status ->
      try {
          def role = new Role(rollName: "Role Name").save(flush: true);
          def user = new User(username: "pritom", name: "Pritom K Mondal", role: role).save(flush: true);
      } catch (Exception ex) {
          ex.printStackTrace();
          try {
              /* Rolling back data if any exception happens */
              status.setRollbackOnly();
          } catch (Exception ex2) {
              ex2.printStackTrace();
          }
      }
   }
}

Sort an ArrayList base on multiple attributes using java/grails

I have an ArrayList of object. The object contain attributes name and classValue. So I want to sort the objects on the classValue, and for all objects in the same classValue I want to sort them on name.


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

/**
 *
 * @author Pritom Kumar
 */
public class MapSort {
    public static void main(String[] args) {
        MapSort mapSort = new MapSort();
        mapSort.sort();
    }
    
    public void sort() {
        List keys = new ArrayList();
        HashMap map1 = new HashMap();
        map1.put("name", "Pritom");
        map1.put("classValue", 5);
        keys.add(map1);
        
        HashMap map2 = new HashMap();
        map2.put("name", "Bappi Lahiri");
        map2.put("classValue", 10);
        keys.add(map2);
        
        HashMap map3 = new HashMap();
        map3.put("name", "Ashok Kumar");
        map3.put("classValue", 5);
        keys.add(map3);

        Collections.sort(keys,
            new Comparator() {
                public int compare(Object left, Object right) {
                    HashMap leftMap = (HashMap) left;
                    HashMap rightMap = (HashMap) right;
                    Integer classValue1 = Integer.parseInt(leftMap.get("classValue").toString());
                    Integer classValue2 = Integer.parseInt(rightMap.get("classValue").toString());
                    int comp = classValue1.compareTo(classValue2);
                    return comp == 0 ? leftMap.get("name").toString().compareTo(rightMap.get("name").toString()) : comp;
                }
            });

        //List the values
        Object[] keyList = keys.toArray();
        for(Integer index = 0; index < keyList.length; index++) {
            System.out.println(keyList[index]);
        }
    }
}


And the output is as following. At first sorts by classValue and then by name.

{name=Ashok Kumar, classValue=5}
{name=Pritom, classValue=5}
{name=Bappi Lahiri, classValue=10}

Tuesday, October 29, 2013

Grails/GORM createCriteria.list to get specific/selected columns only | Alias To Entity Map ALIAS_TO_ENTITY_MAP | Grails Projections | Projections Data

Grails/GORM createCriteria.list to get specific/selected columns only | Alias To Entity Map ALIAS_TO_ENTITY_MAP | Grails Projections | Projections Data.

Below is a example of get some specific field instead of all fields for domain.

And you can left join another domain that is belongsTo or hasMany of parent domain.


You have to import below reference:

import org.hibernate.criterion.CriteriaSpecification

List list = DomainName.createCriteria().list {
    resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
    "in"("id", [1L, 2L])
    createAlias('x', 'x_alias', CriteriaSpecification.LEFT_JOIN)
    projections {
        property("id", "id")
        property("x_alias.field", "field_reference");
    }
}

Output would be like below:

[
    [id:1, field_reference:value1],
    [id:2, field_reference:value2]
] 

Monday, October 28, 2013

Grails get post/put raw request body

There may be situation where the data in body for the request is need to be read. To read the raw data:
request.getReader().text

However, this will give the following error:
getInputStream() has already been called for this request

This is because the default request parser needs to be turned off before reading the body text. Here is one way how to do it in the grails-app/conf/UrlMapping:
class UrlMappings {
    static mappings = {
        "/api/review/$id?"(controller: 'review', parseRequest: false){
            action = [ PUT: "update", POST: "save", GET: "show"]
        }
...
}
By specifying ‘parseRequests: false’ in highlighted line, it will turn off the Grails automatic parsing and make it possible to read the body data (i.e. request.getReader().text)

You can read request body in your filters before method and parse if need as you wish.
 

Friday, October 25, 2013

Grails GORM constrained properties: check if a domain attributes properties mapping

Consider a grails domain class like below:



package com.pritom.domains.customer

class Customer {
    Integer id;
    String customerId
    String email;
    String password
    Date dateCreated = new Date()
    Date lastUpdated = new Date()

    static mapping = {

    }

    static constraints = {
        customerId unique: true
        email unique: true
        creditCard(nullable: true);
    }
}

Now get domain class constrained properties:



def domainClass = new DefaultGrailsDomainClass(com.pritom.domains.Customer)
def constrainedProperties = domainClass.constrainedProperties;

Now check if specific field has some specific property



String key = "customerId";

if (constrainedProperties.containsKey(key)) {
    ConstrainedProperty v = (ConstrainedProperty) constrainedProperties.get(key);
    if(v.isNullable()) println 'Nullable';
    if(v.isBlank()) println 'Blank';
    if(v.isCreditCard()) println 'Credit Card';
    if(v.isDisplay()) println 'Display';
    if(v.isEditable()) println 'Editable';
    if(v.isEmail()) println 'Email';
}


And you can check more properties as you wish.

http://pritomkumar.blogspot.com/2013/09/javagrails-class-constrainedproperty.html

Wednesday, October 23, 2013

Duplicated records/data persistence/flush session error with Grails in synchronized method

Consider some of cases: 

  1. When domain fails to save data because of duplicate record.
  2. When an unsaved domain belongsTo a domain, then showing: 'save the transient instance before flushing'.
Then  - Domain.save(flush:true) - didn't work because of threading.
Here is example of my thread creation:
Thread.start {
    Domain.withTransaction {
         // Doing stuff and calling synchronization method to write data to DB
    }
}
Fix was found here: Grails, GPars and data persistence
I replaced "Domain.withTransaction" with "Domain.withNewSession":
Thread.start {
    Domain.withNewSession {
         // Doing stuff and calling synchronization method to write data to DB
    }
}
and save(flush:true) start writing into mySQL. Since data is written to mySQL, findBy... start returning proper results and therefore I application doesn't try to create duplicated record anymore. Issue solved!

Monday, October 21, 2013

Grails GORM creating foreign key on runtime

GORM mappings let you configure pretty much anything you need in your Grails applications, but occasionally there are more obscure tweaks that aren’t directly supported, and in this case a custom Configuration class is often the solution.

By default Grails uses an instance of GrailsAnnotationConfiguration and the standard approach is to subclass that to retain its functionality and override the secondPassCompile() method.

Create this class (with an appropriate name and package for your application) in src/java or src/groovy:


package com.pritom

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.hibernate.mapping.Column
import org.hibernate.mapping.ForeignKey
import org.hibernate.mapping.PersistentClass

/**
 * Created with IntelliJ IDEA.
 * User: pritom
 * Date: 21/10/13
 * Time: 10:41 AM
 * To change this template use File | Settings | File Templates.
 */
class GormConfiguration extends GrailsAnnotationConfiguration {
    boolean renamedForeignKeys = false

    @Override
    protected void secondPassCompile() {
        super.secondPassCompile()

        if (renamedForeignKeys) {
            return
        }

        renameForeignKeys()
        renamedForeignKeys = true
    }

    void renameForeignKeys() {
        classes.values().each { PersistentClass persistentClass ->
            /**
             * There must be a domain name 'SportUser' which has a field 'user_id'.
             */
            if(persistentClass.entityName.equalsIgnoreCase("com.pritom.SportUser")) {
                persistentClass.table.columns.each {
                    /**
                     * user_id: Column name to behave as a foreign key
                     * There must be a domain name 'User' to linked with it.
                     */
                    if(it.value.name.equalsIgnoreCase("user_id")) {
                        Column column = (Column) it.value;
                        /**
                         * ACL_USER: Foreign key constraints name
                         * com.pritom.User: Domain to make the foreign object
                         */
                        persistentClass.table.createForeignKey("ACL_USER", [column], "com.pritom.User")
                    }
                }
            }
        }
    }

    String createHumanReadableName(ForeignKey key) {
        "${key.columns.first().name}__${key.referencedTable.name}_fkey"
    }
}


What is left is to activate the code which is a one liner, we just have to add a configClass parameter to the datasource configuration:

    dataSource {
        configClass = com.pritom.GormConfiguration
        driverClassName = "com.mysql.jdbc.Driver"
        dbCreate = "create"
        url = "jdbc:mysql://localhost/grails_db"
        username = "grails"
        password = "grails"
    }  

Grails: renaming foreign keys constraints

In Grails if we create a domain class with association we will get a foreign key for the association. Let’s see how the foreign key gets named using an example using a many-to-one association.
Here is a simple domain class with an association to itself.

package gorm

class Category {
    Category child
}
The create table for this class will look like this:
CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT fk302bcfeabee40a7 FOREIGN KEY (child_id)
        REFERENCES category (id)
)
We can see that the primary key gets a human readable name category_pkey but the name of the foreign key is fk302bcfeabee40a7. Not too readable. It would be nice if we could give the foreign key a human readable name too. What about <COLUMN>_<TARGET_TABLE>_fkey to make it similar to the name of the primary key?
It looks like Grails does not offer any GORM DSL sugar to customize the name of the foreign key. But naming it manually on each domain class may be a bit cumbersome anyway. It would be nice if we could make it use the <COLUMN>__<TARGET_TABLE>_fkey format automatically.

Here is a version in groovy implementing the format given above:

package com.pritom

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.hibernate.mapping.PersistentClass
import org.hibernate.mapping.ForeignKey

/**
 * Created with IntelliJ IDEA.
 * User: pritom
 * Date: 21/10/13
 * Time: 10:41 AM
 * To change this template use File | Settings | File Templates.
 */
class GormConfiguration extends GrailsAnnotationConfiguration {
    boolean renamedForeignKeys = false

    @Override
    protected void secondPassCompile() {
        super.secondPassCompile()

        if (renamedForeignKeys) {
            return
        }

        renameForeignKeys()
        renamedForeignKeys = true
    }

    void renameForeignKeys() {
        classes.values().each { PersistentClass persistentClass ->
            persistentClass.table.foreignKeyIterator.each { ForeignKey key ->
                key.name = createHumanReadableName(key)
            }
        }
    }

    String createHumanReadableName(ForeignKey key) {
        "${key.columns.first().name}__${key.referencedTable.name}_fkey"
    }
}
It is not perfect. We do not check the length of the generated name and there are are probably other details I do not know anything about yet we have to take care of. But it it a start. :-)
The create table now look like this:
CREATE TABLE category (
    id bigint NOT NULL,
    version bigint NOT NULL,
    child_id bigint,
    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT child_id__category_fkey FOREIGN KEY (child_id)
        REFERENCES category (id)
)
With a nicely named foreign key. :-)
What is left is to activate the code which is a one liner, we just have to add a configClass parameter to the datasource configuration:
    dataSource {
        configClass = com.pritom.GormConfiguration
        driverClassName = "com.mysql.jdbc.Driver"
        dbCreate = "create"
        url = "jdbc:mysql://localhost/grails_db"
        username = "grails"
        password = "grails"
    }  

Registering new bean classes in grails application programmatically by registerBeanDefinition

As part of amazing goodies of grails is the ability to extend your applications - registering new classes problematically is a breeze


GenericApplicationContext context = new GenericApplicationContext();

context.setParent(applicationContext);
/* OR */
context.setParent(grailsApplication.mainContext);

// Create class from string
Class clazz = new GrailsAwareClassLoader().parseClass(classString);

// First create a bean definition
def myBeanDef = new GenericBeanDefinition()

// Set bean class
myBeanDef.setBeanClass(clazz)

// Set scope
myBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON)

context.registerBeanDefinition("beandefName", myBeanDef);

Wednesday, October 9, 2013

The Grails Hibernate Dynamica/On Fly CriteriaBuilder

The HibernateCriteriaBuilder is a great Grails feature, that you should know when working with the Grails framework. It is an alternative way to create dynamic or static queries with a groovy syntax based on the Criteria API of Hibernate.


Although there is some documentation about it in the Grails Pages, this does not demonstrate some advanced features like joins or pagination. There are several blog posts about the HibernateCriteriaBuilder, but most of them only show a simple example. I want to share my experience with a more complex example that demonstrates some features like:
  • query attributes of associated entities using joins
  • pagination parameters and their consequences
  • reuse of the criteria definition for similar domain classes

Query attributes of associated entities using joins

The example code uses a parcel instance as an example to carry parameter values to construct the criteria.

def example = new Parcel(parcelNumber: '1234%');

def crit = Parcel.createCriteria()
def parcels = crit.list {
  ilike("parcelNumber", example.parcelNumber)
  gt("parcelPrice", example.parcelPrice)
  recipient {
    ilike("lastName", example.recipient.lastName)
  }
  depot {
     address {
       ilike("city", example.depot.address.city)
       ilike("postalCode", example.depot.address.postalCode)
     }
  }
}

Dynamic query parameters

We extend the example to include the filtering only when the value of the example object is not empty.
def example = new Parcel(parcelNumber: '1234%');


def crit = Parcel.createCriteria()

def parcels = crit.list {
    if (example.parcelNumber) ilike("parcelNumber", example.parcelNumber)
    if (example.parcelPrice) gt("parcelPrice", example.parcelPrice)
    if (example.recipient) {
        recipient {
            if (example.recipient?.lastName) {
                ilike("lastName", example.recipient.lastName)
            }
        }
    }
    if (example.depot?.address) {
        depot {
            address {
                if (example.depot.address.city) {
                    ilike("city", example.depot.address.city)
                }
                if (example.depot.address.postalCode) {
                    ilike("postalCode", example.depot.address.postalCode)
                }
            }
        }
    }
}

Reuse of the criteria definition

We have 2 domain classes with the same properties: Parcel and ParcelArchive. We want to reuse the criteria definition, but we must be careful, because extracting it with your IDE ("extract method" refactoring) could break your code. You can use the groovy with.{closure} to extract the criteria:


// search Parcel

def example = new Parcel(parcelNumber: '1234%');

def crit = Parcel.createCriteria()
def parcels = crit.list {
    buildSearchCriteria(example, crit)
}

// search ParcelArchive

def example = new ParcelArchive(parcelNumber: '1234%');

def crit = ParcelArchive.createCriteria()
def parcels = crit.list {
    buildSearchCriteria(example, crit)
}

// criteria method for both

private static void buildSearchCriteria(def example, HibernateCriteriaBuilder crit) {
    crit.with {  
    // make the criteriaBuilder the receiver, because the definitions have been extracted a method
        if (example.parcelNumber) {
            ilike("parcelNumber", example.parcelNumber)
            if (example.parcelPrice) {
                gt("parcelPrice", example.parcelPrice)
            }
            if (example.recipient) {
                recipient {
                    if (example.recipient?.lastName) {
                        ilike("lastName", example.recipient.lastName)
                    }
                }
            }
            if (example.depot?.address) {
                depot {
                    address {
                        if (example.depot.address.city) i {
                            like("city", example.depot.address.city)
                        }
                        if (example.depot.address.postalCode) {
                            ilike("postalCode", example.depot.address.postalCode)
                        }
                    }
                }
            }
        }
    }
} 

Check and create criteria dynamically



package com.pritom
 
import grails.orm.HibernateCriteriaBuilder
import org.codehaus.groovy.grails.commons.GrailsApplication

class DataService { 
    /**
     * Now if you want to search schoolName against a Student you 
     * have to something like below:
     */
    def searchStudentBySchoolName() {
        def key = "discpline.school.name";
        def value = "Some Value";
        def criteria = Student.createCriteria();
        criteria.list {
            buildSearchCriteria(criteria, key.trim("."), value);
        }
    }

    /**
     * isDomainClass() ? Somehow check that the name is a domain class
     * Otherwise it is a property in the domain.
     * 
     * Implement getDomainClassByName() to get the domain class dynamically
     */

    def buildSearchCriteria(HibernateCriteriaBuilder criteria, String[] fields, String value) {
        criteria.with {
            for (Integer index2 = 0; index2 < fields.size() - 1; index2++) {
                if(fields[index2] != null && fields[index2 + 1] != null && isDomainClass(fields[index2])
                        && !isDomainClass(fields[index2 + 1])) {
                    def domainClass = getDomainClassByName(fields[index2].getMetaClass().getTheClass());
                    def domainCriteria = domainClass.createCriteria();
                    'in' (fields[index2], domainCriteria.list {
                        like(fields[index2 + 1], "%" + value + "%")
                    });
                } else if(fields[index2] != null && fields[index2 + 1] != null && isDomainClass(fields[index2])
                        && isDomainClass(fields[index2 + 1])) {
                    def domainClass = getDomainClassByName(fields[index2]).getMetaClass().getTheClass();
                    String current2 = fields[index2];
                    fields[index2] = null;
                    def domainCriteria = domainClass.createCriteria();
                    'in' (current2, domainCriteria.list{
                        buildSearchCriteria(domainCriteria, fields, value)
                    });
                }
            }
        }
    }
} 
 
/* The domain classes are below: */
class Student {
    Integer id;
    String studentId;
    Integer age;
     det belongsTo = [
        discipline: Discipline
    ]
} 
 
class Discipline {
    Integer id;
    String disciplineName; 
 
     def belongsTo = [
        school: School
    ]
}

class School {
    Integer id;
    String schoolName;
} 

http://www.viaboxxsystems.de/the-grails-hibernatecriteriabuilder

Tuesday, October 8, 2013

Groovy Goodness: Sorting a List of Map by specific Key

Sorting a Map by value with Groovy is very simple, due to the added ‘sort’ method on the Map interface.
def hashMap = "fields": {
      "field_3": {
        "order": 4
      },
      "field_2": {
        "order": 3
      },
      "field_1": {
        "order": 2     
    },
      "field_0": {
        "order": 6   
      }
    }

hashMap.sort { a , b -> a.value.order <=> b.value.order }

Sunday, October 6, 2013

Grails and dynamic controller names in UrlMappings

I was creating some REST web services and I needed to map a URL like “/api/1.0/recipes” to a controller called RecipesRestController. It took me a while to work out how to generate a dynamic controller name from the request path. The trick is not to use $controller, it doesn’t seem to work, so instead I renamed it $aController.


class UrlMappings {
    static mappings = {
        "/$controller/$action?/$id?"{
            constraints {
                // apply constraints here
            }
        }
        "/"(view:"/index")
        "500"(view:'/error')
        "/api/1.0/$aController"{
            controller={"${params.aController}Rest"}
            action=[GET:"list", POST:"save"]
        }
        "/api/1.0/$aController/$id"{
            controller={"${params.aController}Rest"}
            action=[GET:"show",  PUT:"update", DELETE:"delete"]
        }
    }
}

 

OR

 
import org.codehaus.groovy.grails.commons.ApplicationHolder

class UrlMappings {
  static mappings = {        
    for( controllerClass in ApplicationHolder.application.controllerClasses) {
      // Admin Controllers first
      if( controllerClass.name.startsWith("Admin")){
        // note... fixes the case so that AdminUserController maps to /admin/user
        "/admin/${controllerClass.name[5].toLowerCase() + controllerClass.name[6..-1]}/$action?/$id?" {
          controller = "admin${controllerClass.name[5..-1]}".toString()
        }
      }
    }
  }
}
 

OR


    "/admin/$controller/$action?/$id?"{
        controller = {
            def controllerName = (request.requestURI - request.contextPath).split('/')[2]

            // or
            //def controllerName = request.servletPath.split('/')[2]

            "${controllerName}Admin"
        }
    }

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