Thursday, 21 June 2018

How to test private constructors in Junit test by reflection in Java

We can not test private constructors directly by JUnit test. We need to use reflection API to call the constructors.


For e.g we have below class which have a private constructor.

package com.company.main;
import java.lang.reflect.InvocationTargetException;
public class MainClass {
private MainClass(){
System.out.println("From private constructor");
}
}


We have the below test case to use reflection to call the private constructor.  If there are any explicit checking is being done by the developer to restrict the calling of private constructor then it may throw exception. 

package com.company.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.junit.jupiter.api.Test;
import com.company.main.MainClass;

class MainTest {

@Test
void test() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

Constructor<MainClass> constructor = MainClass.class.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
MainClass mainClass = constructor.newInstance(new Object[0]);
}
}

How to restrict a private constructor from being called by reflection API in Java


To restrict the private method from being called by reflection API we have to write a method that will check the caller of the method. If the caller is from any other class than the current class then we have to throw the error.

We can get the caller class from the caller stack of Reflection API.

getCallerClass(0) will return class "sun.reflect.Reflection"
getCallerClass(1) will return class "com.company.main.MainClass" // Same class

getCallerClass(1) will return class "jdk.internal.reflect.NativeConstructorAccessorImpl" // If it is being called from any other calss.

check if caller class of 1 and 3 are not the same then throw exception.

package com.company.main;

public class MainClass {

private MainClass(){
checkCallerClass();
System.out.println("From private constructor");
}


private void checkCallerClass() {
               Class self = sun.reflect.Reflection.getCallerClass(1);
               Class caller = sun.reflect.Reflection.getCallerClass(3);
               if (self != caller) {
                    throw new java.lang.IllegalAccessError();
               }
        }

}

Wednesday, 13 June 2018

How to check if a jar file is corrupted

Sometimes jar files get corrupted and we will get errors like below when we will run the file.

 $ java -jar test.jar
Error: Invalid or corrupt jarfile test.jar

When we try to see the content with jar -tvf test.jar.

java.util.zip.ZipException: error in opening zip file
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(ZipFile.java:127)
        at java.util.zip.ZipFile.<init>(ZipFile.java:88)
        at sun.tools.jar.Main.list(Main.java:977)
        at sun.tools.jar.Main.run(Main.java:222)
        at sun.tools.jar.Main.main(Main.java:1147)

Run below command. If this is giving proper output like below then it is not corrupted.
It should give information about the classes present in that jar file and few others.
This jar file may work with -cp command. This usually happens if you use prefix with /META-INF/MANIFEST.MF
testuser@indl123!:testuser> unzip -lv RunDbSttm.jar
Archive:  RunDbSttm.jar
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Defl:N        2   0% 07-20-2016 11:49 00000000  META-INF/
      68  Defl:N       67   2% 07-20-2016 11:49 0a41c062  META-INF/MANIFEST.MF
    3653  Defl:N     2022  45% 07-20-2016 11:48 e8c11d5d  RunDbSttm.class
--------          -------  ---                            -------
    3721             2091  44%                            3 files


How to start a Java program (jar) from another Jar


We can start a jar inside another jar and get the result by below code.

Process proc = new ProcessBuilder("java", "-XMx8192M", "-jar", "test.jar").start();
int result = proc.waitFor();

You can get details of ProcessBuilder from below.

https://docs.oracle.com/javase/10/docs/api/java/lang/ProcessBuilder.html

Difference between class level and object locking and static object lock

1) Class level locking will lock entire class, so no other thread can access any of other synchronized blocks. 2) Object locking will lo...