001package co.codewizards.cloudstore.core.dto; 002 003import static java.util.Objects.*; 004 005import java.lang.reflect.Constructor; 006import java.lang.reflect.InvocationTargetException; 007 008public final class RemoteExceptionUtil { 009 010 private RemoteExceptionUtil() { } 011 012 public static void throwOriginalExceptionIfPossible(final Error error) { 013 Throwable throwable = toThrowable(error); 014 015 if (throwable instanceof RuntimeException) 016 throw (RuntimeException) throwable; 017 018 if (throwable instanceof java.lang.Error) 019 throw (java.lang.Error) throwable; 020 021 throw new RuntimeException(throwable); 022 } 023 024 private static Throwable toThrowable(Error error) { 025 return toThrowable(error, false); 026 } 027 028 private static Throwable toThrowable(Error error, boolean nested) { 029 if (error == null) 030 return null; 031 032 Throwable cause = toThrowable(error.getCause(), true); 033 034 Class<?> clazz; 035 try { 036 clazz = Class.forName(error.getClassName()); 037 } catch (final ClassNotFoundException e) { 038 return new RemoteException(error, true).initCause(cause); 039 } 040 if (!Throwable.class.isAssignableFrom(clazz)) 041 return new RemoteException(error, true).initCause(cause); 042 043 @SuppressWarnings("unchecked") 044 final Class<? extends Throwable> clasz = (Class<? extends Throwable>) clazz; 045 046 Throwable throwable = null; 047 048 // trying XyzException(String message, Throwable cause) 049 if (throwable == null) 050 throwable = getObjectOrNull(clasz, new Class<?>[] { String.class, Throwable.class }, error.getMessage(), cause); 051 052 // trying XyzException(String message) 053 if (throwable == null) 054 throwable = getObjectOrNull(clasz, new Class<?>[] { String.class }, error.getMessage()); 055 056 // trying XyzException(Throwable cause) 057 if (throwable == null) 058 throwable = getObjectOrNull(clasz, new Class<?>[] { Throwable.class }, cause); 059 060 // trying XyzException() 061 if (throwable == null) 062 throwable = getObjectOrNull(clasz, null); 063 064 // LAST: falling back to RemoteException 065 if (throwable == null) 066 throwable = new RemoteException(error, true); 067 068 try { 069 throwable.initCause(cause); 070 } catch (final Exception x) { 071 // This happens, if either the cause was already set in an appropriate constructor (see above) 072 // or the concrete Throwable does not support it. If we were unable to set the cause we want, 073 // we better use a RemoteException and not the original one. 074 if (throwable.getCause() != cause) 075 return new RemoteException(error, true).initCause(cause); 076 } 077 initStackTrace(throwable, error, nested); 078 return throwable; 079 } 080 081 private static void initStackTrace(Throwable throwable, Error error, boolean replaceOriginalStackTrace) { 082 requireNonNull(throwable, "throwable"); 083 requireNonNull(error, "error"); 084 085 int idx = -1; 086 StackTraceElement[] origStackTrace = replaceOriginalStackTrace ? new StackTraceElement[0] : throwable.getStackTrace(); 087 StackTraceElement[] stackTrace = new StackTraceElement[origStackTrace.length + error.getStackTraceElements().size()]; 088 089 for (ErrorStackTraceElement errorStackTraceElement : error.getStackTraceElements()) { 090 stackTrace[++idx] = new StackTraceElement( 091 errorStackTraceElement.getClassName(), 092 errorStackTraceElement.getMethodName(), 093 errorStackTraceElement.getFileName(), 094 errorStackTraceElement.getLineNumber() 095 ); 096 } 097 098 for (StackTraceElement stackTraceElement : origStackTrace) { 099 stackTrace[++idx] = stackTraceElement; 100 } 101 102 throwable.setStackTrace(stackTrace); 103 } 104 105 private static <T> T getObjectOrNull(final Class<T> clazz, Class<?>[] argumentTypes, final Object ... arguments) { 106 T result = null; 107 if (argumentTypes == null) 108 argumentTypes = new Class<?> [0]; 109 110 if (argumentTypes.length == 0) { 111 try { 112 result = clazz.newInstance(); 113 } catch (final InstantiationException e) { 114 return null; 115 } catch (final IllegalAccessException e) { 116 return null; 117 } 118 } 119 120 if (result == null) { 121 Constructor<T> constructor; 122 try { 123 constructor = clazz.getConstructor(argumentTypes); 124 } catch (final NoSuchMethodException e) { 125 return null; 126 } catch (final SecurityException e) { 127 return null; 128 } 129 130 try { 131 result = constructor.newInstance(arguments); 132 } catch (final InstantiationException e) { 133 return null; 134 } catch (final IllegalAccessException e) { 135 return null; 136 } catch (final IllegalArgumentException e) { 137 return null; 138 } catch (final InvocationTargetException e) { 139 return null; 140 } 141 } 142 143 return result; 144 } 145}