public class JarByteClassloader extends ClassLoader {
public JarInputStream jis;
public JarByteClassloader(JarInputStream jarInputStream) throws IOException {
super(Thread.currentThread().getContextClassLoader());
this.jis = jarInputStream;
}
}
Which is used in here:
public void executeMainClass(CustomCodeRequest request) {
String classToLoad = null;
String methodName = request.getMethodName();
final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try{
Pair<String,JarInputStream> pair = extractMainClassManifest(jar);
classToLoad = pair.getFirst();
JarByteClassloader loader = new JarByteClassloader(pair.getSecond());
Class c = loader.loadClass(classToLoad);
Thread.currentThread().setContextClassLoader(loader);
JarEntryObject jarEntry = (JarEntryObject) c.newInstance();
List<JarCodeMethod> methods = jarEntry.methods();
for (JarCodeMethod cc : methods) {
// This code throws NoClassDefFoundError
String ccMethodName = cc.getMethodName();
if (methodName.equals(ccMethodName)) {
}
}
} catch (Exception e) {
e.printStackTrace();
} finally{
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
}
Throws:
Caused by: java.lang.NoClassDefFoundError: com/apex/backends/methods/ProcessBranch
at com.apex.backends.MyJarEntryObject.methods(MyJarEntryObject.java:22)
What could be the root cause of the NoClassDefFoundError? And how can it be fixed?
Where the jar is is like
public class MyJarEntryObject extends JarEntryObject{ #Override
public List methods() { List
methods = new LinkedList(); methods.add(new
ProcessMethod()); return methods; } }
Related
I am writing a JUnit for a method that uses FileInputStream and in the constructor only the file name is passed. The file is created as part of a servlet request and this file is not stored any where.
I am trying to Mock FileInputStream using PowerMockito so that it gives me a mocked file object. Unfortunately I get FileNotFoundException which is valid but I am not sure how to test this method then because the file doesn't exist.
Method under test:
public String viewReport() throws Exception {
this.inputStream = new FileInputStream(DOCUSIGN_REPORT_FILE);
try {
boolean returnReport = validateRequest();
if (returnReport) {
intgList = this.generateViewIntegrationReportData(getESignUIConfig());
this.createCSVFile(intgList, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return null;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return null;
}
return UiIntegrationKeyConstants.REPORT_REPSONSE;
}
JUnit test so far.
#Test
public void testViewReport() throws Exception {
Map<String, Object> actionMap = new HashMap<>();
actionMap.put("application", "ESignatureIntegrationAction");
ActionContext.setContext(new ActionContext(actionMap));
FileInputStream inputStream = Mockito.mock(FileInputStream.class);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(inputStream);
action = new ESignatureIntegrationAction();
action.viewReport();
}
I get an exception when the code reaches to new FileInputStream(DOCUSIGN_REPORT_FILE);
Thanks for the help.
I would suggest to refactor your code in a way that allows testing without a mocking framework.
It could look somewhat like this:
public class YourClass {
// ...
public String viewReport() {
try {
boolean isValidRequest = validateRequest();
if (isValidRequest) {
IntegrationReportCsvFileHandler fileHandler = new IntegrationReportCsvFileHandler();
IntegrationReportData inputData = fileHandler.readData(new FileInputStream(DOCUSIGN_REPORT_FILE));
IntegrationReportGenerator generator = new IntegrationReportGenerator();
IntegrationReportData outputData = generator.processData(inputData, getESignUIConfig());
fileHandler.writeReport(outputData, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
return UiIntegrationKeyConstants.REPORT_RESPONSE;
}
// ...
}
public class IntegrationReportData {
// your custom data structure
// may as well just be a List<Data>
// may be different for input and output
}
public class IntegrationReportException extends Exception {
// your custom exception
public IntegrationReportException(String message) { super(exception); }
}
public class IntegrationReportGenerator {
public IntegrationReportData processData(IntegrationReportData data, ESignConfig config) throws IntegrationReportException {
// here's your logic that requires testing
}
}
public class IntegrationReportCsvFileHandler {
public IntegrationReportData readData(InputStream input) throws IOException {
// read data from given input stream
}
public void writeData(IntegrationReportData data, OutputStreamWriter outputWriter) throws IOException {
// write data to given output stream
}
}
That way the IntegrationReportGenerator would be easily testable.
I have a method
import org.apache.logging.log4j.Logger;
public class SendEmail
{
Logger log = LogManager.getRootLogger();
public static String getStackTrace(final Throwable throwable)
{
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
throwable.printStackTrace(pw);
return sw.getBuffer().toString();
}
public static void main(String[] args)
{
try
{
//Some Code
}
catch (Exception e)
{
log.error(getStackTrace(e));
}
}
}
and I want to add getStackTrace() method to Logger by inheritance (Note : Logger is Interface not Class) so I can call it by log object so I can replace log.error(getStackTrace(e)) ; by log.error(log.getStackTrace(e)) ;
any help ?
The simple way is to use logger.error("message", exception) but if you want your custom method you will need create your own class and keep the original logger inside. There is an error and debug methods, but if you need others you will need to create by yourself (like warn).
public class MyLogger {
final Logger target;
public MyLogger(Logger target) {
this.target = target;
}
public void error(Object message) {
target.error(message);
}
public void debug(Object message) {
target.debug(message);
}
//...
public String getStackTrace(final Throwable throwable) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
throwable.printStackTrace(pw);
return sw.getBuffer().toString();
}
}
In another class:
private static final MyLogger logger = new MyLogger(LogManager.getRootLogger());
public void someMethod() {
try {
//
}
catch (Exception e) {
logger.error(logger.getStackTrace(e));
}
}
Run the main function in File2 , the problem is : threads stuck at "rval=MVEL.executeExpression(compiledExpression, vars);" , 10 threads run in sequential order, not parallel , I wanna know why this happened.
PS: I'm using MVEL 2.2 , the latest version
File1:MVELHelper.java
public class MVELHelper {
private static ParserContext _ctx = new ParserContext(false);
//public static Object execute(String expression, Map<String, Object> vars, Databus databus) throws Exception {
public static Object execute(String expression, Map<String, Object> vars) throws Exception {
Object rval = null;
try {
if(vars == null) {
rval = MVEL.eval(expression, new HashMap<String,Object>());
}
else {
rval = MVEL.eval(expression, vars);
}
return rval;
}
catch(Exception e) {
throw new Exception("MVEL FAILED:"+expression,e);
}
}
public static Serializable compile(String text, ParserContext ctx)
throws Exception {
if(ctx == null) {
//ctx = _ctx;
ctx=new ParserContext(false);
}
Serializable exp = null;
try {
exp = MVEL.compileExpression(text, ctx);
//exp = MVEL.compileExpression(text);
}
catch (Exception e) {
throw new Exception("failed to compile expression.", e);
}
return exp;
}
public static Object compileAndExecute(String expression, Map<String, Object> vars) throws Exception {
Object rval = null;
try {
Serializable compiledExpression=compile(expression,null);
System.out.println("[COMPILE OVER, Thread Id="+Thread.currentThread().getId()+"] ");
if(vars == null) {
rval=MVEL.executeExpression(compiledExpression, new HashMap<String,Object>());
//rval = MVEL.eval(exp, new HashMap<String,Object>());
}
else {
//rval=MVEL.executeExpression(compiledExpression, vars,(VariableResolverFactory)null);
rval=MVEL.executeExpression(compiledExpression, vars);
//rval = MVEL.eval(expression, vars);
}
return rval;
}
catch(Exception e) {
throw new Exception("MVEL FAILED:"+expression,e);
}
}
}
File2:ExecThread3.java
public class ExecThread3 implements Runnable{
Map dataMap=null;
public Map getDataMap() {
return dataMap;
}
public void setDataMap(Map dataMap) {
this.dataMap = dataMap;
}
#Override
public void run() {
Map varsMap = new HashMap();
Map dataMap=new HashMap();
dataMap.put("count",100);
varsMap.put("dataMap", dataMap);
String expression="System.out.println(\"[BEFORE Thread Id=\"+Thread.currentThread().getId()+\"] \"+dataMap.get(\"count\"));"+
"Thread.sleep(3000);"+
"System.err.println(\"[AFTER Thread Id=\"+Thread.currentThread().getId()+\"] \"+dataMap.get(\"count\"));";
try {
//MVEL.compileExpression(expression);
MVELHelper.compileAndExecute(expression, varsMap);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int k=0;k<10;k++){
ExecThread3 execThread=new ExecThread3();
new Thread(execThread).start();
}
}
}
I have a simple singleton:
class Test1 implements Serializable {
private static Test1 instance;
public String a = "a";
public String b = "b";
public String c = null;
public String d = null;
public String e;
public String f;
private Test1() {
e = "e";
}
public static Test1 getInstance() {
if (instance == null) {
instance = new Test1();
}
return instance;
}
// http://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-with-examples
protected Object readResolve() {
return getInstance();
}
public String toString() {
return String.format("Test1{ a:%s, b:%s, c:%s, d:%s, e:%s, f:%s}", a, b, c, d, e, f);
}
}
My main():
if ((new File("t1.obj").exists() == false)) {
Test1 t1 = Test1.getInstance();
t1.b = "bb";
t1.d = "dd";
t1.f = "ff";
serialize("t1.obj", t1);
}
else {
Test1 t2 = deserialize("t1.obj");
}
First run looks well
Serialized hu.fehergeri13.abptc.server.Test1 object to t1.obj file.
Test1{ a:a, b:bb, c:null, d:dd, e:e, f:ff}
after second run:
Deserialized hu.fehergeri13.abptc.server.Test1 object from t1.obj file.
Test1{ a:a, b:b, c:null, d:null, e:e, f:null}
My serialize/deserialize:
public static void serialize(String filePath, Object o) {
try {
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(o);
System.out.println(String.format("Serialized %s object to %s file.", o.getClass().getName(), filePath));
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static <T> T deserialize(String filePath) {
try {
FileInputStream is = new FileInputStream(filePath);
ObjectInputStream ois = new ObjectInputStream(is);
T o = (T) ois.readObject();
System.out.println(String.format("Deserialized %s object from %s file.", o.getClass().getName(), filePath));
ois.close();
is.close();
return o;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Why are the values keep default and not bb,dd,ff?
My serializable singleton:
public class MySingleton implements Serializable {
private static final long serialVersionUID = -5909418239300111453L;
private static MySingleton instance = null;
protected MySingleton() {
}
public static MySingleton getInstance() {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
protected Object readResolve() {
return getInstance();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
instance = this;
}
private String attr;
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
this.attr = attr;
}
}
I'm trying to load a jar file directly into memory without dropping it to the HDD. I have tried using the ClassLoader, but i get an error.
This is my code:
Custom Classloader
public class CLS_ClassLoader extends ClassLoader {
private byte[] bArrData;
public CLS_ClassLoader(ClassLoader parent, byte[] bArrData) {
super(parent);
this.bArrData = bArrData;
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return defineClass(name, bArrData, 0,
bArrData.length);
}
}
Main
ClassLoader tParentClsLoader = CLS_ClassLoader.class.getClassLoader();
CLS_ClassLoader tClsLoader = new CLS_ClassLoader(tParentClsLoader, fileToByteArray("D:/App.jar"));
Class<?> tClass = null;
try {
tClass = tClsLoader.loadClass("pkg_main.CLS_Main");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Output
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1347093252 in class file pkg_main/CLS_Main
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at pkg_main.CLS_ClassLoader.loadClass(CLS_ClassLoader.java:20)
at pkg_main.CSL_Main.main(CSL_Main.java:27)
My idea is to take a encrypted jar file , decrypted it on runtime and load directly into memory.
Sorry for the typos, I did not speak English well. Thanks in advance!
Your main mistake is that defineClass(...) is expecting class bytes and you're feeding it with the whole jar file. The actual exception is thrown if class bytes do not start with 0xCAFEBABE, typical Java class file header. So, you need an additional step to sort the classes out of the jar file. The following implementation demonstrates the idea:
class CCLoader extends ClassLoader {
private Map<String, byte[]> classes = new HashMap<String, byte[]>();
public CCLoader(InputStream in) {
super(CCLoader.class.getClassLoader());
try {
JarInputStream jis = new JarInputStream(in);
JarEntry je = null;
String entryName = null;
while ((je = jis.getNextJarEntry()) != null) {
entryName = je.getName();
if (je.getName().endsWith(".class")) {
byte[] classBytes = readClass(jis);
String canonicalName = entryName.replaceAll("/", ".").replaceAll(".class", "");
classes.put(canonicalName, classBytes);
}
}
jis.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private byte[] readClass(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while(true){
int qwe = stream.read();
if(qwe == -1) break;
baos.write(qwe);
}
return baos.toByteArray();
}
public Class loadClass(String name) throws ClassNotFoundException {
try {
return this.getParent().loadClass(name);
} catch (ClassNotFoundException e) {
return findClass(name);
}
}
public Class findClass(String name) throws ClassNotFoundException {
byte[] classBytes = classes.get(name);
return defineClass(name, classBytes, 0, classBytes.length);
}
}
Following your example you can try it like that:
ClassLoader tClsLoader = new CCLoader(new FileInputStream("C:/commons-io-2.0.1.jar"));
Class<?> tClass = tClsLoader.loadClass("org.apache.commons.io.FileExistsException");