I'm trying to read a serialized Java file containing instances of classes I don't have in my classpath while reading.
Is there a way (perhaps by writing my own ObjectInputStream?) to ignore those ClassNotFoundException and replace the corresponding object of the stream by null ?
The object I want to read is similar to this one :
public class Log {
private String someField;
private Throwable throwable;
}
Actually, that Log object is read, but I don't have in my classpath the concrete class of some Log.throwable values. I would want that in that case, the throwable field value would be null but I want my Log object with the other fields read.
If I catch the exception, I couldn't even have my Log object.
Actually, I have tried multiple way to do this (extend ObjectInputStream and implement ObjectInputStream.readClassDescriptor() in order to return a Proxy of an ObjectStreamClass which would return null for default method ObjectStreamClass.getResolveException(), using Javassist because JDK cannot proxify classes, but the problem is : ObjectStreamClass cannot be instantiated outside of java.io package).
But I finally found a (rather ugly) way to do this :
public class DecompressibleObjectInputStream extends ObjectInputStream {
private static Logger logger = LoggerFactory.getLogger(DecompressibleObjectInputStream.class);
public DecompressibleObjectInputStream(InputStream in) throws IOException {
super(in);
try {
// activating override on readObject thanks to https://stackoverflow.com/a/3301720/535203
Field enableOverrideField = ObjectInputStream.class.getDeclaredField("enableOverride");
enableOverrideField.setAccessible(true);
Field fieldModifiersField = Field.class.getDeclaredField("modifiers");
fieldModifiersField.setAccessible(true);
fieldModifiersField.setInt(enableOverrideField, enableOverrideField.getModifiers() & ~Modifier.FINAL);
enableOverrideField.set(this, true);
} catch (NoSuchFieldException e) {
warnCantOverride(e);
} catch (SecurityException e) {
warnCantOverride(e);
} catch (IllegalArgumentException e) {
warnCantOverride(e);
} catch (IllegalAccessException e) {
warnCantOverride(e);
}
}
private void warnCantOverride(Exception e) {
logger.warn("Couldn't enable readObject override, won't be able to avoid ClassNotFoundException while reading InputStream", e);
}
#Override
public void defaultReadObject() throws IOException, ClassNotFoundException {
try {
super.defaultReadObject();
} catch (ClassNotFoundException e) {
logger.warn("Potentially Fatal Deserialization Operation.", e);
}
}
#Override
protected Object readObjectOverride() throws IOException, ClassNotFoundException {
// copy of JDK 7 code avoiding the ClassNotFoundException to be thrown :
/*
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
*/
try {
int outerHandle = getObjectInputStreamFieldValue("passHandle");
int depth = getObjectInputStreamFieldValue("depth");
try {
Object obj = callObjectInputStreamMethod("readObject0", new Class<?>[] {boolean.class}, false);
Object handles = getObjectInputStreamFieldValue("handles");
Object passHandle = getObjectInputStreamFieldValue("passHandle");
callMethod(handles, "markDependency", new Class<?>[] {int.class, int.class}, outerHandle, passHandle);
ClassNotFoundException ex = callMethod(handles, "lookupException", new Class<?>[] {int.class}, passHandle);
if (ex != null) {
logger.warn("Avoiding exception", ex);
}
if (depth == 0) {
callMethod(getObjectInputStreamFieldValue("vlist"), "doCallbacks", new Class<?>[] {});
}
return obj;
} finally {
getObjectInputStreamField("passHandle").setInt(this, outerHandle);
boolean closed = getObjectInputStreamFieldValue("closed");
if (closed && depth == 0) {
callObjectInputStreamMethod("clear", new Class<?>[] {});
}
}
} catch (NoSuchFieldException e) {
throw createCantMimicReadObject(e);
} catch (SecurityException e) {
throw createCantMimicReadObject(e);
} catch (IllegalArgumentException e) {
throw createCantMimicReadObject(e);
} catch (IllegalAccessException e) {
throw createCantMimicReadObject(e);
} catch (InvocationTargetException e) {
throw createCantMimicReadObject(e);
} catch (NoSuchMethodException e) {
throw createCantMimicReadObject(e);
} catch (Throwable t) {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
if (t instanceof IOException) {
throw (IOException)t;
}
throw createCantMimicReadObject(t);
}
}
private IllegalStateException createCantMimicReadObject(Throwable t) {
return new IllegalStateException("Can't mimic JDK readObject method", t);
}
#SuppressWarnings("unchecked")
private <T> T getObjectInputStreamFieldValue(String fieldName) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field declaredField = getObjectInputStreamField(fieldName);
return (T) declaredField.get(this);
}
private Field getObjectInputStreamField(String fieldName) throws NoSuchFieldException {
Field declaredField = ObjectInputStream.class.getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField;
}
#SuppressWarnings("unchecked")
private <T> T callObjectInputStreamMethod(String methodName, Class<?>[] parameterTypes, Object... args) throws Throwable {
Method declaredMethod = ObjectInputStream.class.getDeclaredMethod(methodName, parameterTypes);
declaredMethod.setAccessible(true);
try {
return (T) declaredMethod.invoke(this, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
#SuppressWarnings("unchecked")
private <T> T callMethod(Object object, String methodName, Class<?>[] parameterTypes, Object... args) throws Throwable {
Method declaredMethod = object.getClass().getDeclaredMethod(methodName, parameterTypes);
declaredMethod.setAccessible(true);
try {
return (T) declaredMethod.invoke(object, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
Then I overrode the ObjectInputStream.readClassDescriptor() in order to ignore differences between serialVersionUID also (as described in that answer) and I've got an ObjectInputStream which can read nearly everything !
I don't think there is a way to do this ... apart from cloning and modifying the Java serialization implementation.
Certainly, readObject and readResolve hooks won't help, because they rely on methods of the class that you cannot load.
Related
In my Java project SonarQube says that an expression is always false. However I cannot see why. This is the code in question:
BaseException baseException = null;
for (SpaceInfo i: spaceInfos) {
try {
processSingle(i.getSpaceKey(), i.getContentType());
} catch (BaseException e) {
baseException = BaseException.chain(baseException, e);
}
}
// Here sonar say that this condition will always evaluate to false.
if (baseException != null) {
throw baseException;
}
However in my opinion if the processSingle method throws a BaseException then baseException should not be null and therefore the expression should not evaluate to false.
The processSingle method is declared as follows:
private void processSingle(String spaceKey, String contentType) throws BaseException
And there are definitely cases in which the processSingle method will throw a BaseException. So I think that Sonar is mistaken. Or is there something going on here that I am not seeing?
Update:
This is what BaseException.chain() does:
public static BaseException chain (BaseException a, BaseException b) {
if (a == null) { return b; }
a.setNextException(b);
return a;
}
And this is the code of processSingle:
private void processSingle(String spaceKey, String contentType) throws BaseException {
assert ContentTypes.Page.equals(contentType) || ContentTypes.BlogPost.equals(contentType);
Content content;
try {
content = createEmptyContent(spaceKey, contentType);
} catch (Exception e) {
throw new MessageToContentProcessorProcessSingleException(contentType, spaceKey, e);
}
BaseException baseException = null;
try {
contentCreator.addMetadata(content);
} catch (BaseException e) {
baseException = BaseException.chain(baseException, e);
}
Pair<List<AttachmentInfo>, FailedToSaveAttachmentException> pair = contentCreator.saveAttachments(messageParser.getContent(), content);
List<AttachmentInfo> attachments = pair.getLeft();
baseException = BaseException.chain(baseException, pair.getRight());
try {
String html = htmlGenerator.generateHtml(attachments, messageParser.getContent());
contentCreator.updateBodyOfContent(content, html);
} catch (BaseException e) {
baseException = BaseException.chain(baseException, e);
}
if (baseException != null) {
throw new MessageToContentProcessorProcessSingleException(contentType, spaceKey, baseException);
}
}
Just for testing/curiosity, I would try:
} catch (BaseException e) {
baseException = e;
}
this would show if Sonar thinks the exception can be thrown or not. Or if it is getting confused by the chain method or assignment statement (assigning to basseException but using it (still null) on the right side of assignment).
I know this is changing the logic, just for testing
even try (but I do not believe this would trick Sonar)
} catch (BaseException e) {
var tmp = BaseException.chain(baseException, e);
baseException = tmp;
}
Try changing chain() to help SonarQube:
public static BaseException chain (BaseException a, BaseException b) {
if (a == null) {
return b;
} else {
a.setNextException(b);
return a;
}
}
thinking about it, hardly possible to be the problem - almost trivial that a is not null here
I would try and see if it works:
BaseException baseException;
for (SpaceInfo i: spaceInfos) {
try {
processSingle(i.getSpaceKey(), i.getContentType());
baseException = null;
} catch (BaseException e) {
baseException = BaseException.chain(baseException, e);
}
}
I know it is required that in a non-void method, return or throw is a must.
But I don't like the dummy return in catch block in such case:
public int call() throws Exception {
try {
return calcMethod();
} catch (Exception e) {
process(e);
return 0;
}
}
protected void process(Exception e) throws xxxException {
if ( isTypeAException(e) ) { throw new TypeAException() ; }
else if ( isTypeBException(e) ) { throw new TypeBException() ; }
else ( isTypeCException(e) ) { throw new TypeCException() ; }
}
...
process will certainly throws an exception, then why return is still required in catch block?
In one sense, throwing the exception in process() is to be construed as "a problem with processing", which is also not what you mean.
As you want the exception to be raised by call(), so the solution here is to make process() an exception factory:
public int call() throws Exception {
try {
return calcMethod();
} catch (Exception e) {
throw process(e);
}
}
protected xxxException process(Exception e) throws xxxException {
if (isTypeAException(e))
return new TypeAException();
else if (isTypeBException(e))
return new TypeBException();
else
return new TypeCException();
}
This question already has answers here:
Replacing if else statement with pattern
(5 answers)
Converting many 'if else' statements to a cleaner approach [duplicate]
(7 answers)
Refactoring code in Java, alternatives to large if statement
(9 answers)
What is the best way to replace or substitute if..else if..else trees in programs?
(21 answers)
How to remove large if-else-if chain [duplicate]
(6 answers)
Closed 5 years ago.
I'm trying to clean up some Java code. There are many static factory methods that all do the same exception handling. As an example, consider createA:
public static A createA() throws XXXX, YYYY {
try {
return somethingThatThrows();
} catch (InterruptedException | ExecutionException e) {
Throwable throwable = e.getCause();
if (throwable instanceOf XXXX) {
throw (XXXX) throwable;
} else if (e instance of YYYY) {
throw (YYYY) throwable;
} else if (throwable != null) {
throw new RuntimeException(throwable);
} else {
throw new RuntimeException(e);
}
}
}
There are many of these create methods (each of which returns a different type). For each of these methods, a copy of this exception handling exists (i.e. it's duplicated). I'm hoping there is a way to avoid all of this identical code and only have this logic in one place.
Of course, without exception handling, you simply extract the logic to a helper function and the duplication is solved - the fact that this has exception handling makes it different. The following code does not build:
public static void helper(final Exception e) {
Throwable throwable = e.getCause();
if (throwable instanceOf XXXX) {
throw (XXXX) throwable;
} else if (e instance of YYYY) {
throw (YYYY) throwable;
} else if (throwable != null) {
throw new RuntimeException(throwable);
} else {
throw new RuntimeException(e);
}
}
public static A createA() throws XXXX, YYYY {
try {
return somethingThatThrows();
} catch (InterruptedException | ExecutionException e) {
handle(e);
}
}
Does anyone have any suggestions?
This can be handled in a functional way as below:
#FunctionalInterface
interface SomethingThatThrows<T> {
T execute() throws XXXX, YYYY, InterruptedException,ExecutionException;
}
private static <T> T handledFuntion(SomethingThatThrows<T> function) throws XXXX, YYYY {
try {
return function.execute();
} catch (InterruptedException | ExecutionException e) {
Throwable throwable = e.getCause();
if (throwable instanceof XXXX) {
throw (XXXX) throwable;
} else if (e instanceof YYYY) {
throw (YYYY) throwable;
} else if (throwable != null) {
throw new RuntimeException(throwable);
} else {
throw new RuntimeException(e);
}
}
}
// Use lambda literal - may be better when arguments are involved
public A createA(String arg1) throws XXXX, YYYY {
return handledFuntion(() -> {
// write code just like you'd write it in try{} body -
// all arguments to createA() are available
return new A(arg1);
});
}
// use a method handle, works best when there are no arguments
public B createB() throws XXXX, YYYY {
return handledFuntion(this::somethingThatMakesB);
}
private B somethingOtherThatMakesB() throws XXXX, YYYY, InterruptedException,ExecutionException {
// Some logic that creates and returns B
}
Edit: Incorporated #Arkadiy's answer.
Try to extract the common logic into a private method and call it:
public static A createA() throws XXXX, YYYY {
try {
return somethingThatThrows();
} catch (InterruptedException | ExecutionException e) {
processInterruptedExcutionExceptions(e);
}
return null;
}
private static void processInterruptedExcutionExceptions(final Exception e) throws XXXX, YYYY {
Throwable throwable = e.getCause();
if (throwable instanceOf XXXX) {
throw (XXXX) throwable;
} else if (e instance of YYYY) {
throw (YYYY) throwable;
} else if (throwable != null) {
throw new RuntimeException(throwable);
} else {
throw new RuntimeException(e);
}
}
try
{
if(ruleName.equalsIgnoreCase("RuleName"))
{
cu.accept(new ASTVisitor()
{
public boolean visit(MethodInvocation e)
{
if(rule.getConditions().verify(e, env, parentKeys, astParser, file, cu)) // throws ParseException
matches.add(getLinesPosition(cu, e));
return true;
}
});
}
// ...
}
catch(ParseException e)
{
throw AnotherException();
}
// ...
I need to catch thrown exception in the bottom catch, but I cannot overload method via throws construction. How to do with that, please advice? Thanks
Create custom exception, write try catch block in anonymous class and catch it in your catch block.
class CustomException extends Exception
{
//Parameterless Constructor
public CustomException () {}
//Constructor that accepts a message
public CustomException (String message)
{
super(message);
}
}
now
try
{
if(ruleName.equalsIgnoreCase("RuleName"))
{
cu.accept(new ASTVisitor()
{
try {
public boolean visit(MethodInvocation e)
{
if(rule.getConditions().verify(e, env, parentKeys, astParser, file, cu)) // throws ParseException
matches.add(getLinesPosition(cu, e));
return true;
}
catch(Exception e){
throw new CustomException();
}
});
}
// ...
}
catch(CustomException e)
{
throw AnotherException();
}
As suggested already, an unchecked exception could be used. Another option is to mutate a final variable. Eg:
final AtomicReference<Exception> exceptionRef = new AtomicReference<>();
SomeInterface anonymous = new SomeInterface() {
public void doStuff() {
try {
doSomethingExceptional();
} catch (Exception e) {
exceptionRef.set(e);
}
}
};
anonymous.doStuff();
if (exceptionRef.get() != null) {
throw exceptionRef.get();
}
If I have 2 classes, "A" and "B", how can I create a generic factory so I will only need to pass the class name as a string to receive an instance?
Example:
public static void factory(String name) {
// An example of an implmentation I would need, this obviously doesn't work
return new name.CreateClass();
}
Thanks!
Joel
Class c= Class.forName(className);
return c.getDeclaredConstructor().newInstance();//assuming you aren't worried about constructor .
javadoc
For invoking constructor with argument
public static Object createObject(Constructor constructor,
Object[] arguments) {
System.out.println("Constructor: " + constructor.toString());
Object object = null;
try {
object = constructor.newInstance(arguments);
System.out.println("Object: " + object.toString());
return object;
} catch (InstantiationException e) {
//handle it
} catch (IllegalAccessException e) {
//handle it
} catch (IllegalArgumentException e) {
//handle it
} catch (InvocationTargetException e) {
//handle it
}
return object;
}
}
have a look
You may take a look at Reflection:
import java.awt.Rectangle;
public class SampleNoArg {
public static void main(String[] args) {
Rectangle r = (Rectangle) createObject("java.awt.Rectangle");
System.out.println(r.toString());
}
static Object createObject(String className) {
Object object = null;
try {
Class classDefinition = Class.forName(className);
object = classDefinition.newInstance();
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
return object;
}
}