How is Throwable.getSuppressed() supported from Android API 31 - java

When testing a code that does nasty reflective operations on Throwable fields, then it is failing on Android API 31. The reason is that Throwable.suppressedExceptions field is no longer present.
I did more tests between Android API 30 and 31:
public class ThrowableInternalTest {
private static final String TAG = "ThrowableInternal";
#Test
public void suppressedExceptionsFieldIsPresent() throws Exception {
Log.w(TAG, "Android API: " + VERSION.SDK_INT);
// Checking internal fields
Field[] fields = Throwable.class.getDeclaredFields();
String fieldNames = Stream.of(fields).map(Field::getName).collect(Collectors.joining(","));
Log.w(TAG, "Throwable fields: " + fieldNames);
// Manually setting suppressed exceptions
Exception suppressed = new Exception();
Exception exception = new Exception();
exception.addSuppressed(suppressed);
Log.w(TAG, "exception.getSuppressed(): " + exception.getSuppressed().length);
// Using try-with-resource block which should have suppressed exceptions
try {
try (ThrowingClosable ignored = new ThrowingClosable()) {
throw new Exception();
}
} catch (Throwable t) {
Log.w(TAG, "try-with-resource suppressed: " + t.getSuppressed().length);
}
// Results:
// minSdkVersion: 18
// Android API: 30
// Throwable fields: backtrace,cause,detailMessage,stackTrace,suppressedExceptions,serialVersionUID
// exception.getSuppressed(): 0
// try-with-resource suppressed: 0
// minSdkVersion: 19
// Android API: 30
// Throwable fields: backtrace,cause,detailMessage,stackTrace,suppressedExceptions,serialVersionUID
// exception.getSuppressed(): 1
// try-with-resource suppressed: 1
// minSdkVersion: 18
// Android API: 31
// Throwable fields: backtrace,cause,detailMessage,stackTrace,serialVersionUID
// exception.getSuppressed(): 0
// try-with-resource suppressed: 0
// minSdkVersion: 19
// Android API: 31
// Throwable fields: backtrace,cause,detailMessage,stackTrace,serialVersionUID
// exception.getSuppressed(): 1
// try-with-resource suppressed:1
}
private static class ThrowingClosable implements AutoCloseable {
#Override
public void close() throws Exception {
throw new Exception();
}
}
}
When minSdkVersion is below 19, then Throwable.getSuppressed() always returns an empty array. With higher minSdkVersion, then it is working properly.
Although, the suppressedExceptions field is only present on API 30, not on 31.
But in the Android SDK source code, the suppressedExceptions field is present on both API: 30 and 31.
I'm curious how API 31 could have suppressed exception working even without the suppressedExceptions field ?
Also why suppressed exceptions are not supported when minSdkVersion is below 19 ?

Related

How to catch exceptions thrown from reactor?

I want to catch exceptions thrown from a flux, my code is like this:
try {
Flux.just("key1", "key2", "key3")
.doOnNext(System.out::println)
.map(k -> {
if (!k.equals("key1")) {
throw new RuntimeException("Not key1"); // 1
}
return "External Value, key:" + k;
})
.subscribe(System.out::println); // 2
} catch (Throwable e) {
System.out.println("Got exception"); // 3
}
the output is:
key1
External Value, key:key1
key2
[ERROR] (main) Operator called default onErrorDropped - reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.RuntimeException: Not key1
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.RuntimeException: Not key1
Caused by: java.lang.RuntimeException: Not key1
at com.cxd.study.reactor.HandlingErrors.lambda$catchException$7(HandlingErrors.java:153)
...
It seems that my catch at step 3 is never reached.
I know I can reach the exception at step 2 like this:.subscribe(System.out::println, e -> System.out.println("Got Exception")).
But how can I catch the exception thrown at step 1 out of the flux?
You can use the onError() operator to handle error cases, or the doOnError() operator if you e.g. want to log the exception.

Retry with resilience4j doesn't work with some exceptions

I am using the resilience4j library to retry some code, I have the following code below, I expect it to run 4 times. If I throw IllegalArgumentException it works but if I throw ConnectException it doesn't.
object Test extends App {
val retryConf = RetryConfig.custom()
.maxAttempts(4)
.retryOnException(_ => true)
//.retryExceptions(classOf[ConnectException])
.build
val retryRegistry = RetryRegistry.of(retryConf)
val retryConfig = retryRegistry.retry("test", retryConf)
val supplier: Supplier[Unit] = () => {
println("Run")
throw new IllegalArgumentException("Test")
//throw new ConnectException("Test")
}
val decoratedSupplier = Decorators.ofSupplier(supplier).withRetry(retryConfig).get()
}
I expected that retry to retry on all exceptions.
You are creating decorated supplier which is only catching RuntimeExceptions whilst ConnectException is not a RuntimeException:
... decorateSupplier(Retry retry, Supplier<T> supplier) {
return () -> {
Retry.Context<T> context = retry.context();
do try {
...
} catch (RuntimeException runtimeException) {
...
Look through the Retry.java and choose one that catches Exception for example decorateCheckedFunction, for example
val registry =
RetryRegistry.of(RetryConfig.custom().maxAttempts(4).build())
val retry = registry.retry("my")
Retry.decorateCheckedFunction(retry, (x: Int) => {
println(s"woohoo $x")
throw new ConnectException("Test")
42
}).apply(1)
which outputs
woohoo 1
woohoo 1
woohoo 1
woohoo 1
Exception in thread "main" java.rmi.ConnectException: Test
Personally I use softwaremill/retry

JBoss EAP 6.4 with Hibernate - Hide a specific Oracle exception in log file

Playing with PersistenceException -> SQLException -> getErrorCode(), I'm hiding a specific Oracle error in my log. Problem is, in my server.log I still found rows like:
WARN 25 Sep 2018 12:14:47,121 - id - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ms 5829302 SQL Error: 13333, SQLState: 72000
ERROR 25 Sep 2018 12:14:47,121 - id - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ms 5829302 ORA-13333: invalid LRS measure
ORA-06512: at "MDSYS.SDO_LRS", line 3149
ORA-06512: at line 1
which aren't specifically logged by me.
Here is my code:
try {
try {
//business stuff
} catch (PersistenceException persEx) {
if (persEx.getCause() != null && persEx.getCause() instanceof GenericJDBCException) {
GenericJDBCException jdbcEx = (GenericJDBCException) persEx.getCause();
SQLException sqlEx = (SQLException) jdbcEx.getCause();
if (sqlEx.getErrorCode() == 13333) {
//handling ORA-13333: invalid LRS measure as an info
log.info("Possible invalid LRS measure");
} else {
throw persEx; // do not swallow unhandled exceptions
}
} else {
throw persEx; // do not swallow unhandled exceptions
}
} catch (Exception e) {
log.error("Other exception:" + e.getMessage());
}
} catch (Exception e) {
log.error("Exception to log:" + e.getMessage());
}
Solved by adding a specific filter to the JBoss log handler, in this case
<filter-spec value="all(not(match("ORA-13333")), not(match("SQL Error: 13333")))"/>
I hope it can be useful to someone else.

Can't instantiate class error in JSF, caused by NullPointerException

Here is my managed Bean class,
public class ChartBean implements Serializable {
private PieChartModel pieModel;
public ChartBean(){
createPieModel();
}
public PieChartModel getPieModel() {
return pieModel;
}
private void createPieModel(){
try {
pieModel = new PieChartModel();
String query = "SELECT b.countryname,count(b.countryname) FROM info.summery a,info.countrymcc b;";
Connector conn = new Connector();
Statement str = (Statement) conn.getConn().createStatement();
ResultSet res = str.executeQuery(query);
while(res.next()){
pieModel.set(res.getString(1), Integer.parseInt(res.getString(2)));
}
} catch (SQLException ex) {
Logger.getLogger(ChartBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
But the problem is when it is compiled it gives an error like this "Cant instantiate class: org.primefaces.examples.view.ChartBean". What is the reason??
StackTrace:
Caused by: java.lang.NullPointerException at
org.primefaces.examples.view.ChartBean.createPieModel(ChartBean.java:45) at
org.primefaces.examples.view.ChartBean.<init>(ChartBean.java:32) at
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorI‌​
mpl.java:39) at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorA‌​
ccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at
java.lang.Class.newInstance0(Class.java:355) at java.lang.Class
By a process of elimination, the problem is happening because conn.getConn() is returning null. You should be able to simply confirm that the exception occurs at that line (by checking the line number!), and we know that conn cannot be null, so it must be result of getConn() that is null.
That's about as far as I can go without knowing what the Connector class is and how its getConn() method works.
For the record, here's how I eliminated other possibilities.
The NPE is being thrown in the createPieModel call ... and not in some method called from createPieModel:
1. private void createPieModel(){
2. try {
3. pieModel = new PieChartModel();
4. String query = "SELECT b.countryname,count(b.countryname) FROM info.summery a,info.countrymcc b;";
5. Connector conn = new Connector();
6. Statement str = (Statement) conn.getConn().createStatement();
7. ResultSet res = str.executeQuery(query);
8. while(res.next()){
9. pieModel.set(res.getString(1), Integer.parseInt(res.getString(2)));
10. }
11. } catch (SQLException ex) {
12. Logger.getLogger(ChartBean.class.getName()).log(Level.SEVERE, null, ex);
13. }
14. }
It cannot be line 3 because any NPE would be thrown in the constructor.
It cannot be line 4
It cannot be line 5 - see line 3
It could be line 6
It cannot be line 7 - because str must be non-null (if we get that far)
It cannot be line 8 - because executeQuery never returns null
It cannot be line 9 - because res and pieModel must be non-null.
It cannot be line 12 - because nothing there can return a null.
Hence it can only happen on line 6.

How to get the line number in error in java?

I know that the line in error is to_return = find(list,false); How can I get the line number of this line when there is NullPointerException type of error? Or in line number in general?
I tried few things. The closest is this one Called.getLineNumber() which gives me the line number of StackTraceElement Called = new Throwable().fillInStackTrace().getStackTrace()[0];
public TestObject[] myfind(Subitem list )throws Exception{
TestObject[]to_return=null;
try {
to_return = find(list,false);
}
catch (RationalTestException ex) {
//logStoreException(ex);
StackTraceElement Called = new Throwable().fillInStackTrace().getStackTrace()[0];
StackTraceElement Calling = new Throwable().fillInStackTrace().getStackTrace()[1];
throw new Exception (this.add_debugging_info(Called, Calling, ex.getMessage()));
}
catch (NullPointerException npe) {
StackTraceElement Called = new Throwable().fillInStackTrace().getStackTrace()[0];
StackTraceElement Calling = new Throwable().fillInStackTrace().getStackTrace()[1];
logStoreException(npe);
System.out.println("Line number: "+npe.getStackTrace()[0].getLineNumber());
System.out.println("Line number2: "+Integer.toString(Called.getLineNumber()));
System.out.println(this.add_debugging_info(Called, Calling, npe.getMessage()));
throw new Exception (this.add_debugging_info(Called, Calling, npe.getMessage()));
}
catch (Exception ex) {
StackTraceElement Called = new Throwable().fillInStackTrace().getStackTrace()[0];
StackTraceElement Calling = new Throwable().fillInStackTrace().getStackTrace()[1];
throw new Exception (this.add_debugging_info(Called, Calling, ex.getMessage()));
}
finally {
//unregisterAll();
//unregister(to);
return to_return;
}
}
If you just want the current stack trace, use Thread.currentThread().getStackTrace()
If you want to force the JVM to fill in the stack traces, please set the option -XX:-OmitStackTraceInFastThrow on your JVM.
When running in Eclipse, to get the line number itself, you need to get the StackTrace array and call getLineNumber() on it.
The following worked for me in my Utils class, isSessionConnectible method:
... catch (ClassFormatError cfe) {
logger.error("Problem ClassFormatError connecting. " + cfe.getMessage() + " " + cfe.getCause());
int size = cfe.getStackTrace().length - 1;
logger.error(" Root cause: " + cfe.getStackTrace()[size].getMethodName() + " " + cfe.getStackTrace()[size].getClassName());
if (size>1) {
logger.error(" Penultimate cause: method=" + cfe.getStackTrace()[size-1].getMethodName() + " class=" + cfe.getStackTrace()[size-1].getClassName() +
" line=" + cfe.getStackTrace()[size-1].getLineNumber());
}
Result when thrown:
2018-07-06 12:00:12 ERROR Utils:319 - Problem ClassFormatError connecting to Hibernate. Absent Code attribute in method that is not native or abstract in class file javax/transaction/SystemException null
2018-07-06 12:00:12 ERROR Utils:322 - Root cause: main <mypackage>.Utils
2018-07-06 12:00:12 ERROR Utils:324 - Penultimate cause: method=isSessionConnectible class=<mypackage>.Utils line=306
BTW, in Eclipse, make sure that Window --> Preferences --> Java --> Compiler has the checkbox marked at "Add line number attributes to generated class files".

Categories

Resources