Remote exceptions
Before reading this chapter please become familiar with chapters shown below:
JLupin has functionality (JLupinDefaultServiceExceptionHandlerImpl
) which makes it possible to handle/throw any remote exceptions. You can also precisely detect where exception was created based on stack trace (which includes IP and name of the machine). Thanks to this feature it is easy and fast to determine where the bug is located and where to look for corresponding log. Let's see below examples:
JUnit Client -> Sample Native Microservice communication
We assume that native microservice is named sampleNative
. Below image shows environment configuration and how the request is passed.
SampleNativeExceptionService
interface
This service is located inside sampleNative
.
package com.jlupin.interfaces.microservice.samplenative.service.various;
import com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException;
public interface SampleNativeExceptionService {
void generateException1() throws SampleExceptionNativeServiceException;
void generateException2() throws Exception;
void generateException3();
void generateException4();
}
SampleNativeExceptionService
implementation
This service is located inside sampleNative
.
package com.jlupin.impl.microservice.samplenative.service.impl.various;
import com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException;
import com.jlupin.interfaces.microservice.samplenative.service.various.SampleNativeExceptionService;
import com.jlupin.interfaces.microservice.samplesecondnative.service.SampleSecondNativeExceptionService;
import com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service(value = "nativeExceptionService")
public class SampleNativeExceptionServiceImpl implements SampleNativeExceptionService {
@Override
public void generateException1() throws SampleExceptionNativeServiceException {
throw new SampleExceptionNativeServiceException("exception 1 from service:SampleNativeExceptionService");
}
@Override
public void generateException2() throws Exception {
throw new Exception("exception 2 from service:SampleNativeExceptionService");
}
@Override
public void generateException3() {
throw new IllegalStateException("exception 3 from service:SampleNativeExceptionService");
}
@Override
public void generateException4() {
throw new MyException("exception 4 from service:SampleNativeExceptionService");
}
private class MyException extends RuntimeException{
public MyException(String message) {
super(message);
}
}
}
JUnit's code (chosen fragments):
public class JunitTest() {
private JLupinDelegator jLupinRmcDelegator;
@Before
public void before() throws Throwable {
jLupinRmcDelegator = JLupinClientUtil.generateOuterMicroserviceLoadBalancerDelegator(5000, 3, 5000,PortType.JLRMC, 1000, 3000000,
new JLupinMainServerInZoneConfiguration[]{
new JLupinMainServerInZoneConfiguration("NODE_1", "127.0.0.1", 9090, 9095, 9096, 9097)
}
}
try {
jLupinRmcDelegator.start();
} catch (JLupinDelegatorException e) {
e.printStackTrace();
}
}
private SampleNativeExceptionService getSampleNativeExceptionService() {
return JLupinClientUtil.generateRemote(jLupinRmcDelegator, "sampleNative", "nativeExceptionService" , SampleNativeExceptionService.class);
}
@Test
public void testOfException() {
SampleNativeExceptionService sampleNativeExceptionService = getSampleNativeExceptionService();
try {
sampleNativeExceptionService.generateException1();
} catch (SampleExceptionNativeServiceException e) {
e.printStackTrace();
}
try {
sampleNativeExceptionService.generateException2();
} catch (Exception e) {
e.printStackTrace();
}
try {
sampleNativeExceptionService.generateException3();
} catch (Exception e) {
e.printStackTrace();
}
try {
sampleNativeExceptionService.generateException4();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Stack trace for sampleNatvieExceptionService.generateException1()
As you can see in section suppressed
JLupin shows the place where the exception was created (machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
):
com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException: exception 1 from service:SampleNativeExceptionService
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateException1(SampleNativeExceptionServiceImpl.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:214)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:108)
at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:51)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:44)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:21)
at com.jlupin.impl.entrypoint.microservice.jlrmc.JLupinJLRMCMicroserviceEntryPointImpl.doEntry(JLupinJLRMCMicroserviceEntryPointImpl.java:40)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:101)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:83)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Stack trace for sampleNativeExceptionService.generateException2()
java.lang.Exception: exception 2 from service:SampleNativeExceptionService
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateException2(SampleNativeExceptionServiceImpl.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:214)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:108)
at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:51)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:44)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:21)
at com.jlupin.impl.entrypoint.microservice.jlrmc.JLupinJLRMCMicroserviceEntryPointImpl.doEntry(JLupinJLRMCMicroserviceEntryPointImpl.java:40)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:101)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:83)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Stacktrace for sampleNativeExceptionService.generateException3()
In this example undeclared exception of type RuntimeException
(IllegalStateException
) is thrown:
java.lang.IllegalStateException: exception 3 from service:SampleNativeExceptionService
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateException3(SampleNativeExceptionServiceImpl.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:214)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:108)
at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:51)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:44)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:21)
at com.jlupin.impl.entrypoint.microservice.jlrmc.JLupinJLRMCMicroserviceEntryPointImpl.doEntry(JLupinJLRMCMicroserviceEntryPointImpl.java:40)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:101)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:83)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Stacktrace for sampleNativeExceptionService.generateException4()
In this example undeclared exception of type RuntimeException
(private class MyExcpetion
) is thrown. Class MyException
is not available on client's classpath. It is located only in scope of called microservice. Let's take a look on stack trace:
com.jlupin.interfaces.client.command.exception.JLupinCommandException: [exception handler message begin] unexpected error occurred while trying to execute service:nativeExceptionService and method:generateException4, error details from service:com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl$MyException: exception 4 from service:SampleNativeExceptionService
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateException4(SampleNativeExceptionServiceImpl.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:214)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:108)
at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:51)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:44)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:21)
at com.jlupin.impl.entrypoint.microservice.jlrmc.JLupinJLRMCMicroserviceEntryPointImpl.doEntry(JLupinJLRMCMicroserviceEntryPointImpl.java:40)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:101)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:83)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Suppressed: java.io.NotSerializableException: com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.jlupin.impl.util.JLupinUtil.getByteArrayFromObjectWithHandlingException(JLupinUtil.java:383)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:86)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
[exception handler message end]
at com.jlupin.impl.client.command.JLupinCommandImpl.executeWitResult(JLupinCommandImpl.java:55)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteServiceInvocationHandlerImpl.invoke(JLupinRemoteServiceInvocationHandlerImpl.java:99) at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteServiceInvocationHandlerImpl.invoke(JLupinRemoteServiceInvocationHandlerImpl.java:99)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:28)
at com.sun.proxy.$Proxy4.generateException4(Unknown Source)
at com.jlupin.test.integration.IntegrationTest.testOfException(IntegrationTest.java:270)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
First of all JLupinExceptionHandler
discovered that exception MyException
is a private class of service SampleNativeExceptionServiceImpl
. Due to this before sending this exception to the client as serialized byte array it tries to serialize it. This operation fails (class SampleNativeExceptionServiceImpl
doesn't implement Serializable
interface which is right!) so it adds reason of failed serialization as a suppressed warning:
Suppressed: java.io.NotSerializableException: com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.jlupin.impl.util.JLupinUtil.getByteArrayFromObjectWithHandlingException(JLupinUtil.java:383)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:86)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
Because of that above exception (in serialized form) is not send to the client's side, Jlupin's classes which are calling remote objects detect it and throw exception of type RuntimeException
(JLupinCommandException
). It contains all relevant information about what and where happened (including IP and name of the machine).
So the main reason of exception:
error details from service:com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl$MyException: exception 4 from service:SampleNativeExceptionService
from code:
@Override
public void generateException4() {
throw new MyException("exception 4 from service:SampleNativeExceptionService");
}
is served to client in clear and readable form.
Sections [exception handler message begin]
and [exception handler message end]
are served by exception handler on given microservice to make exceptions which went through many microservices readable. We will see it on the other example.
JUnit Client-> Sample Native Microservice -> Sample Second Native Microservice communication
Below image shows environment configuration and how the request is passed.
SampleNativeExceptionService
interface
This service is located inside sampleNative
. Let's add another method to our interface:
void generateExceptionFromSecondSampleMicroserviceWithHandlingException() throws SampleExceptionNativeServiceException;
public interface SampleNativeExceptionService {
void generateException1() throws SampleExceptionNativeServiceException;
void generateException2() throws Exception;
void generateException3() ;
void generateException4() ;
void generateExceptionFromSecondSampleMicroserviceWithHandlingException() throws SampleExceptionNativeServiceException;
}
SampleNativeExceptionService
implementation
This service is located inside sampleNative
. It will call microservice sampleSecondMicroservice
.
@Service(value = "nativeExceptionService")
public class SampleNativeExceptionServiceImpl implements SampleNativeExceptionService {
@Autowired
private SampleSecondNativeExceptionService sampleSecondNativeExceptionService;
@Override
public void generateException1() throws SampleExceptionNativeServiceException {
throw new SampleExceptionNativeServiceException("exception 1 from service:SampleNativeExceptionService");
}
@Override
public void generateException2() throws Exception {
throw new Exception("exception 2 from service:SampleNativeExceptionService");
}
@Override
public void generateException3() {
throw new IllegalStateException("exception 3 from service:SampleNativeExceptionService");
}
@Override
public void generateException4() {
throw new MyException("exception 4 from service:SampleNativeExceptionService");
}
@Override
public void generateExceptionFromSecondSampleMicroserviceWithHandlingException() throws SampleExceptionNativeServiceException {
try {
sampleSecondNativeExceptionService.generateException();
} catch (SampleSecondNativeExceptionServiceException e) {
throw new SampleExceptionNativeServiceException("an error occurred during invoking generateException method caused by:",e);
}
}
private class MyException extends RuntimeException{
public MyException(String message) {
super(message);
}
}
}
Field:
@Autowired
private SampleSecondNativeExceptionService sampleSecondNativeExceptionService;
is a remote reference to service which is located on sampleSecondNative
.
Configuration of remote call in Spring's configuration (sampleNative
):
@Configuration
@ComponentScan({"com.jlupin.impl.microservice.samplenative"})
public class MicroserviceApplicationConfiguration {
@Bean
public JLupinDelegator getLupinDelegator() {
return JLupinClientUtil.generateInnerMicroserviceLoadBalancerDelegator(PortType.JLRMC);
}
@Bean(name="sampleSecondNativeExceptionService")
public SampleSecondNativeExceptionService getSampleSecondNativeExceptionService() {
return JLupinClientUtil.generateRemote(getLupinDelegator(),"sampleSecondNative",
"sampleSecondNativeExceptionService",
SampleSecondNativeExceptionService.class);
}
@Bean(name = "jLupinRegularExpressionToRemotelyEnabled")
public List getRemotelyBeanList() {
List<String> list = new ArrayList<String>();
list.add("nativeExceptionService");
return list;
}
}
SampleSecondNativeExceptionService
interface
This service is located inside sampleSecondNative
.
package com.jlupin.interfaces.microservice.samplesecondnative.service;
import com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException;
public interface SampleSecondNativeExceptionService {
void generateException() throws SampleSecondNativeExceptionServiceException;
}
SampleSecondNativeExceptionService
implementation
This service is located inside sampleSecondNative
.
@Service("sampleSecondNativeExceptionService")
public class SampleSecondNativeExceptionServiceImpl implements SampleSecondNativeExceptionService {
@Override
public void generateException() throws SampleSecondNativeExceptionServiceException {
throw new SampleSecondNativeExceptionServiceException("something goes wrong in sample second native exception service");
}
}
As you can see interface SampleSecondNativeExceptionService
throws exception SampleSecondNativeExceptionServiceException
which sampleNative
microservice has on it's own side (on classpath). For the record call from sampleNative
:
@Override
public void generateExceptionFromSecondSampleMicroserviceWithHandlingException() throws SampleExceptionNativeServiceException {
try {
sampleSecondNativeExceptionService.generateException();
} catch (SampleSecondNativeExceptionServiceException e) {
throw new SampleExceptionNativeServiceException("an error occurred during invoking generateException method caused by:",e);
}
}
Above method packs exception SampleSecondNativeExceptionServiceException
into exception SampleExceptionNativeServiceException
. It is correctly serialized to byte array form on sampleNative
's exception handler's side due to fact that it has all required classes: SampleSecondNativeExceptionServiceException
, SampleExceptionNativeServiceException
on it's own side.
Byte array is correctly send to the client's side (JUnit Client) but during deserialization it turns out that class SampleSecondNativeExceptionServiceException
is not available on client's classpath so classes which are calling remote JLupin objects tries to change source exception SampleExceptionNativeServiceException
which contains SampleSecondNativeExceptionServiceException
to exception of type RuntimeException
(JLupinCommandException
). It will contains all relevant information - let's see how JLupin joined all stack trace's from all microservices which were involved in communication and created remote stack trace with information about local problem with deserialization:
Execution
com.jlupin.interfaces.client.command.exception.JLupinCommandException: [exception handler message begin] unexpected error occurred while trying to execute service:nativeExceptionService and method:generateExceptionFromSecondSampleMicroserviceWithHandlingException, error details from service:com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException: an error occurred during invoking generateException method caused by:
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateExceptionFromSecondSampleMicroserviceWithHandlingException(SampleNativeExceptionServiceImpl.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.jlupin.impl.util.JLupinUtil.invokeMethod(JLupinUtil.java:214)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:108)
at com.jlupin.impl.processor.JLupinDefaultServiceProcessorImpl.invoke(JLupinDefaultServiceProcessorImpl.java:51)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.base.JLupinInvokeServiceStrategyBaseImpl.executeService(JLupinInvokeServiceStrategyBaseImpl.java:44)
at com.jlupin.impl.entrypoint.microservice.jlrmc.strategy.invoke.impl.JLupinInvokeServiceStrategyInCurrentThreadImpl.invokeService(JLupinInvokeServiceStrategyInCurrentThreadImpl.java:21)
at com.jlupin.impl.entrypoint.microservice.jlrmc.JLupinJLRMCMicroserviceEntryPointImpl.doEntry(JLupinJLRMCMicroserviceEntryPointImpl.java:40)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:101)
at com.jlupin.impl.server.jnative.defaults.strategy.service.base.JLupinBaseAbstractServiceStrategy$ThreadCallable.call(JLupinBaseAbstractServiceStrategy.java:83)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Caused by: com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException: something goes wrong in sample second native exception service
at com.jlupin.impl.microservice.samplesecondnative.service.impl.SampleSecondNativeExceptionServiceImpl.generateException(SampleSecondNativeExceptionServiceImpl.java:13)
... 16 more
Suppressed: java.lang.Exception: error occurred on microservice:sampleSecondNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
[exception handler message end]
at com.jlupin.impl.client.command.JLupinCommandImpl.executeWitResult(JLupinCommandImpl.java:55)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteServiceInvocationHandlerImpl.invoke(JLupinRemoteServiceInvocationHandlerImpl.java:99)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:28)
at com.sun.proxy.$Proxy4.generateExceptionFromSecondSampleMicroserviceWithHandlingException(Unknown Source)
at com.jlupin.test.integration.IntegrationTest.testOfException(IntegrationTest.java:276)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Suppressed: java.lang.Exception: an error occurred during create Throwable object from byte array. The reason may be that Throwable thrown from service not exists on client classpath, error caused by:
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:42)
... 24 more
Caused by: java.lang.ClassNotFoundException: com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:626)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:501)
at java.lang.Throwable.readObject(Throwable.java:914)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:38)
... 24 more
Now we see exception on client's side: com.jlupin.interfaces.client.command.exception.JLupinCommandException:
Next we see section from [exception handler message begin]
to [exception handler message end]
- the most important information:
Highest message (the last one):
unexpected error occurred while trying to execute service:nativeExceptionService and method:generateExceptionFromSecondSampleMicroserviceWithHandlingException, error details from service:com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException: an error occurred during invoking generateException method caused by:
at com.jlupin.impl.microservice.samplenative.service.impl.various.SampleNativeExceptionServiceImpl.generateExceptionFromSecondSampleMicroserviceWithHandlingException(SampleNativeExceptionServiceImpl.java:49)
happened on machine with IP 192.168.1.12 and microservice sampleNative
:
Suppressed: java.lang.Exception: error occurred on microservice:sampleNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
because of exception:
Caused by: com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException: something goes wrong in sample second native exception service
at com.jlupin.impl.microservice.samplesecondnative.service.impl.SampleSecondNativeExceptionServiceImpl.generateException(SampleSecondNativeExceptionServiceImpl.java:13)
... 16 more
on machine with IP 192.168.1.12 and microservice sampleSecondNative
:
Suppressed: java.lang.Exception: error occurred on microservice:sampleSecondNative, machine ip:192.168.1.12, name:PR01.home, (canonical name:PR01.home)
at com.jlupin.impl.handler.service.JLupinDefaultServiceExceptionHandlerImpl.handleServiceException(JLupinDefaultServiceExceptionHandlerImpl.java:67)
at com.jlupin.impl.processor.strategy.impl.JLupinDefaultServiceProcessorInvokeStrategyImpl.invoke(JLupinDefaultServiceProcessorInvokeStrategyImpl.java:131)
... 10 more
Local suppressed warning is a deserialization error due to errors discussed earlier:
Suppressed: java.lang.Exception: an error occurred during create Throwable object from byte array. The reason may be that Throwable thrown from service not exists on client classpath, error caused by:
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:42)
... 24 more
Caused by: java.lang.ClassNotFoundException: com.jlupin.interfaces.microservice.samplesecondnative.service.exception.SampleSecondNativeExceptionServiceException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:626)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:501)
at java.lang.Throwable.readObject(Throwable.java:914)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.jlupin.impl.client.proxy.remote.handler.JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.invoke(JLupinRemoteSupportsExceptionServiceInvocationHandlerImpl.java:38)
... 24 more
And all is clear.
SpringBoot -> Sample Native Microservice communication
Possibility of hiding error by Spring Boot as a client - how to handle it?
Spring Boot without configured exception handler is not showing full stack trace in output message (security reasons).
Spring Boot's controller
@RestController
public class ServletExceptionController {
@Autowired
private SampleNativeExceptionService sampleNativeExceptionService;
private final Logger logger = LoggerFactory.getLogger(ServletExceptionController.class);
@PostMapping("/handleExceptionFromNativeMicroservice1")
public ExceptionResponse handleExceptionFromNativeMicroservice1(@RequestBody ExceptionRequest exceptionRequest) throws Throwable {
sampleNativeExceptionService.generateException1();
//The following code is not available because an exception has been raised
ExceptionResponse exceptionResponse = new ExceptionResponse();
exceptionResponse.setStackTrace("fake stack trace");
return exceptionResponse;
}
}
During calling above code client will receive below response:
Execution:
POST /sampleServlet/handleExceptionFromNativeMicroservice1 HTTP/1.1
Host: localhost:8000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 0a8e8713-417f-a03c-ef43-6192bcdf0c4f
{"exception":true}
Response:
{
"timestamp": 1526977990321,
"status": 500,
"error": "Internal Server Error",
"exception": "com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException",
"message": "org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.jlupin.interfaces.microservice.samplenative.service.exception.SampleExceptionNativeServiceException: exception 1 from service:SampleNativeExceptionService",
"path": "/sampleServlet/handleExceptionFromNativeMicroservice1"
}
Without configured exception handler on Spring Boot's side we had received only the result of executing method Throwable.getMessage()
by Spring Boot and there is only highest error message without details which are in full stack trace. The solution is to use Exception Handler and correct handling of exceptions on Spring Boot's side with showing information which are appropriate for application and user.
Exception Handler's documentation for Spring Boot can be found here and here.