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.

Figure 1. JUnit calling sampleNative.

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.

Figure 2. JUnit calling sampleNative which calls sampleSecondNative.

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.