Spring Integration - no response on reply channel - junit

This is a follow up question to Spring Integration Executor Channel using annotations code sample.
System diagram is attached .
I am trying to test the box highlighted in red by posting a message into 'Common channel' and reading from REPLY_CHANNEL set in the msg.
'Common channel' is a publish subscribe channel.
REPLY_CHANNEL is a QueueChannel.
Since this is a JUnit test, I have mocked jdbcTemplate, datasource and the Impl to ignore any DB calls.
My issue is:
When I post a message onto 'Common Channel', I do not receive any message on the REPLY_CHANNEL. The junit keeps waiting for a response.
What should I change to get a response on the REPLY_CHANNEL?
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(loader = AnnotationConfigContextLoader.class) --------- 1
#ActiveProfiles("test")
public class QueuetoQueueTest {
#Configuration
static class ContextConfiguration { ------------------------------------- 2
#Bean(name = "jdbcTemplate")
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplateMock = Mockito.mock(JdbcTemplate.class);
return jdbcTemplateMock;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DataSource dataSourceMock = Mockito.mock(DataSource.class);
return dataSourceMock;
}
#Bean(name = "entityManager")
public EntityManager entityManager() {
EntityManager entityManagerMock = Mockito.mock(EntityManager.class);
return entityManagerMock;
}
#Bean(name = "ResponseChannel")
public QueueChannel getReplyQueueChannel() {
return new QueueChannel();
}
//This channel serves as the 'common channel' in the diagram
#Bean(name = "processRequestSubscribableChannel")
public MessageChannel getPublishSubscribeChannel() {
return new PublishSubscribeChannel();
}
}
#Mock
DBStoreDaoImpl dbStoreDaoImpl;
#Test
public void testDBConnectivity() {
Assert.assertTrue(true);
}
#InjectMocks -------------------------------------------------------------- 3
StoretoDBConfig storetoDBConfig = new StoretoDBConfig();
#Autowired
#Qualifier("ResponseChannel")
QueueChannel ResponseChannel;
#Autowired
#Qualifier("processRequestSubscribableChannel")
MessageChannel processRequestSubscribableChannel;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void outboundtoQueueTest() {
try {
when(dbStoreDaoImpl.storeToDB(any()))
.thenReturn(1); ----------------------------------------------- 4
//create message
Message message = (Message<String>) MessageBuilder
.withPayload("Hello")
.setHeader(MessageHeaders.REPLY_CHANNEL, ResponseChannel)
.build();
//send message
processRequestSubscribableChannel.send(message);
System.out
.println("Listening on InstructionResponseHandlertoEventProcessorQueue");
//wait for response on reply channel
Message<?> response = ResponseChannel.receive(); ----------------------- 5
System.out.println("***************RECEIVED: "
+ response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Load 'ContextConfiguration' for JUnit so that DB is not accessed.
This is how you load custom configuration in JUnit as per https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles
Inside the config class, we mock jdbcTemplate, dataSource, entityManager and define the 'common channel' on which the request is posted and ResponseChannel.
Inject jdbcTemplate, dataSource mock into StoretoDBConfig so that the DB is not hit
Mock DaoImpl class so that DB calls are ignored
The test blocks here because there is no response on the REPLY_CHANNEL
UPDATED CODE:
Code inside 5 (the class that reads from common channel):
#Configuration
class HandleRequestConfig {
//Common channel - refer diagram
#Autowired
PublishSubscribeChannel processRequestSubscribableChannel;
//Step 9 - This channel is used to send queue to the downstream system
#Autowired
PublishSubscribeChannel forwardToExternalSystemQueue;
public void handle() {
IntegrationFlows.from("processRequestSubscribableChannel") // Read from 'Common channel'
.wireTap(flow->flow.handle(msg -> System.out.println("Msg received on processRequestSubscribableChannel"+ msg.getPayload())))
.handle(RequestProcessor,"validateMessage") // Perform custom business logic - no logic for now, return the msg as is
.wireTap(flow->flow.handle(msg -> System.out.println("Msg received on RequestProcessor"+ msg.getPayload())))
.channel("forwardToExternalSystemQueue"); // Post to 'Channel to another system'
}
}
//Code inside step 8 - 'Custom Business Logic'
#Configuration
class RequestProcessor {
public Message<?> validateMessage(Message<?> msg) {
return msg;
}
}
WHAT I AM TRYING TO ACHIEVE:
I have individual junit test cases for the business logic. I am trying to test that when the request is posted into the 'common channel', the response is received on 'channel to another system'.
Why I cannot use the original ApplicationContext: Because it connects to the DB, and I do not want my JUnit to connect to the DB or use an embedded database. I want any calls to the DB to be ignored.
I have set the reply channel to 'ResponseChannel', shouldn't the 'Custom Business Logic' send its response to 'ResponseChannel'?
If I have to listen on a different channel for the response, I am willing to do so. All I want to test is whether the message I am sending on 'common channel' is received on 'channel to other system'.
UPDATE 2:
Addressing Artem's questions.
Thankyou Artem for your suggestions.
Is 'HandlerRequestConfig' included in the test configuration? - We cannot directly call the handle() method. Instead I thought if I post on 'processRequestSubscribableChannel', the handle() method inside HandleRequestConfig will be invoked since it listens on the same channel. Is this wrong? How do I test HandleRequestConfig.handle() method then?
I added wiretap to the end of each step in HandleRequestConfig (code updated). I find that none of the wiretap message is printed. This means that the msg I am posting is not even reaching the input channel 'processRequestSubscribableChannel'. What am I doing wrong?
NOTE: I tried removing the 'processRequestSubscribableChannel' bean inside Configuration (so that the actual 'processRequestSubscribableChannel' in the applicationContext is used). I am getting an unsatisfied dependency error - Expected atleast 1 bean with configuration PublishSubscribeChannel.
Update 3: Posted details Artem requested.
#RunWith(SpringRunner.class)
#SpringBootTest
public class QueuetoQueueTest {
// Step 1 - Mocking jdbcTemplate, dataSource, entityManager so that it doesn't connect to the DB
#MockBean
#Qualifier("jdbcTemplate")
JdbcTemplate jdbcTemplate;
#MockBean
#Qualifier("dataSource")
public DataSource dataSource;
#MockBean
#Qualifier("entityManager")
public EntityManager entityManager;
#Bean(name = "ResponseChannel")
public PublishSubscribeChannel getReplyQueueChannel() {
return new PublishSubscribeChannel();
}
//Mocking the DB class
#MockBean
#Qualifier("dbStoreDaoImpl")
DBStoreDaoImpl dbStoreDaoImpl ;
//Inject the mock objects created above into the flow that stores data into the DB.
#InjectMocks
StoretoDBConfig storetoDBConfig = new StoretoDBConfig();
//Step 2 - Injecting MessageChannel used in the actual ApplicationContext
#Autowired
#Qualifier("processRequestSubscribableChannel")
MessageChannel processRequestSubscribableChannel;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void outboundtoQueueTest() {
try {
when(dbStoreDaoImpl.storeToDB(any()))
.thenReturn(1);
//create message
Message message = (Message<?>) MessageBuilder
.withPayload("Hello")
.build();
//send message - this channel is the actual channel used in ApplicationContext
processRequestSubscribableChannel.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ERROR I AM GETTING: The code tries to connect to the DB and throws an error.
UPDATE 1: Code inside StoretoDBConfig
#Configuration
#EnableIntegration
public class StoretoDBConfig {
#Autowired
DataSource dataSource;
/*
* Below code is irrelevant to our current problem - Including for reference.
*
* storing into DB is delegated to a separate thread.
*
* #Bean
* public TaskExecutor taskExecutor() {
* return new SimpleAsyncTaskExecutor();
* }
*
* #Bean(name="executorChannelToDB")
* public ExecutorChannel outboundRequests() {
* return new ExecutorChannel(taskExecutor());
* }
* #Bean(name = "DBFailureChannel")
* public static MessageChannel getFailureChannel() {
* return new DirectChannel();
* }
* private static final Logger logger = Logger
* .getLogger(InstructionResponseHandlerOutboundtoDBConfig.class);
*/
#Bean
public IntegrationFlow handle() {
/*
* Read from 'common channel' - processRequestSubscribableChannel and send to separate thread that stores into DB.
*
/
return IntegrationFlows
.from("processRequestSubscribableChannel")
.channel("executorChannelToDB").get();
}
}
CODE THAT STORES INTO DB ON THE SEPARATE THREAD:
#Repository
public class DBStoreDaoImpl implements DBStoreDao {
private JdbcTemplate jdbcTemplate;
#Autowired
public void setJdbcTemplate(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
#Transactional(rollbackFor = Exception.class)
#ServiceActivator(inputChannel = "executorChannelToDB")
public void storetoDB(Message<?> msg) throws Exception {
String insertQuery ="Insert into DBTable(MESSAGE) VALUES(?)";
jdbcTemplate.update(insertQuery, msg.toString());
}
}

Please, show us what is subscribed to that Common channel. Your diagram somehow is not related to what you show us. The code you demonstrate is not full.
The real problem with the replyChannel that something really has to send a message to it. If your flow is just one-way - send, store and nothing to return, - then you indeed won't get anything for this one. That's why would to show those channel adapters.
The best way to observe the message journey is to turn on debug logging for the org.springframework.integration category.
Although I see that you declare those channels as is in the ContextConfiguration and there is really no any subscribers to the getRequestChannel. Therefore nobody is going to consume your message and, of course, nobody is going to send you a reply.
Please, reconsider your test class to use the real application context. Otherwise it is fully unclear what you would like to achieve if you really don't test your flow...

Related

How to Mock microservices in Junit

I need to run the integration test of one microservice, without the need to start the dependent microservices.
Below is the approach I have tried(I have provided the skeleton of the classes below)
MicroServiceOneController.java
#Autowired
MicroServiceOneService microServiceOneServiceImpl;
#PostMapping(value = "/saveData/{userEmail}")
public void doHandleSaveData(
#PathVariable("userEmail") String userEmail) {
microServiceOneService.saveData(userEmail);
}
MicroServiceOneServiceImpl.java
#Autowired
MicroServiceTwoProxy microServiceTwoProxy;
#Override
public void saveData(String userEmail){
DemoDTO dtoObject=microServiceTwoProxy.fetchRequiredData();
dtoObject.setUserEmail(userEmail);
// other code to persist dtoObject
}
TestOfMicroServiceOne.java:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class TestOfMicroServiceOne{
#Autowired
private TestRestTemplate restTemplate;
#MockBean
MicroServiceTwoProxy microServiceTwoProxy;
#test
void test(){
Mockito.when(microServiceTwoProxy.fetchRequiredData()).thenReturn(new DemoDTO("1","data"));
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<DemoDTO.class> response =
this.restTemplate.exchange("/persist/saveData/{userEmail}",
HttpMethod.POST, entity, DemoDTO.class, "user#gmail.com");
assertEquals(response.getStatusCode(), HttpStatus.OK);
}
I expected when running the test, when the microServiceTwoProxy.fetchRequiredData() is hit, it should return the new DemoDTO("1","data") as specified in the test.
I want this requirement to run the test of MicroserviceOne without depending upon the status of MicroServiceTwo.
But this doesn't seem to work. It expects the second microservices to be up and test fails with the message Load balancer does not have available server for client
Any other approaches available?

How do I make a JMS ObjectMessage for a Unit Test?

I'm trying to write a unit test for an MDB. The goal of my test is to make sure that the logic in the MDB can identify the correct type of object in the ObjectMessage and process it. However, I can't figure out how to make an ObjectMessage so I can test it. I keep getting null pointer exceptions.
Here is my unit test:
/**
* Test of the logic in the MDB
*/
#RunWith(JMockit.class)
#ExtendWith(TimingExtension.class)
class MDBTest
{
protected MyMDB mdb;
#BeforeEach
public void setup() throws NamingException, CreateHeaderException, DatatypeConfigurationException, PropertiesDataException
{
mdb = new MyMDB();
}
/**
* Test the processing of the messages by the MDB
*/
#Test
void testReceivingMessage() throws JMSException, IOException
{
MyFirstObject testMsg = getTestMessage();
ObjectMessage msg = null;
Session session = null;
new MockUp<ObjectMessage>()
{
#Mock
public void $init()
{
}
#Mock
public Serializable getObject()
{
return testMsg;
}
};
new MockUp<Session>()
{
#Mock
public void $init()
{
}
#Mock
public ObjectMessage createObjectMessage(Serializable object)
{
return msg;
}
};
// !!!! Null pointer here on Session !!!!
ObjectMessage msgToSend = session.createObjectMessage(testMsg);
mdb.onMessage(msgToSend);
assertEquals(1, mdb.getNumMyFirstObjectMsgs());
}
/**
* Create a Test Message
*
* #return the test message
* #throws IOException
*/
protected MyFirstObject getTestMessage) throws IOException
{
MyFirstObject myObj = new MyFirstObject();
myObj.id = 0123;
myObj.description = "TestMessage";
return myObj;
}
}
I feel like I should be able to initialize Session somehow, but I need to do it without using an additional library like Mockrunner.
Any suggestions?
I would try to address this in a different style. Provide a mock client, that will just mock the right API.
We should mock only a set of functions required for message retrieval and processing but that means we might have to provide a custom implementation for some of the APIs available in the EJB/JMS library. The mock client will have a function to push messages on a given topic/queue/channel, message can be simple String.
A simple implementation might look like this, in this other methods have been omitted for simplicity.
// JMSClientImpl is an implementation of Connection interface.
public class MyJmsTestClient extends JMSClientImpl{
Map<String, String> channelToMessage = new ConcurrentHashMap<>();
public Map<String, String> getMessageMap(){
return channelToMessage;
}
public void enqueMessage(String channel, String message){
channelToMessage.put(channe, message);
}
#Override
public Session createSession(){
return new MyTestSession(this);
}
}
// A class that implements some of the methods from session interface
public MyTestSession extends SessionImpl{
private MyJmsTestClient jmsClient;
MyTestSession(MyJmsTestClient jmsClient){
this.jmsClient = jmsClient;
}
// override methods that fetches messages from remote JMS
// Here you can just return messages from MyJmsTestClient
// override other necessary methods like ack/nack etc
MessageConsumer createConsumer(Destination destination) throws JMSException{
// returns a test consume
}
}
A class that implements methods from MessageConsumer interface
class TestMessageConsumer extends MessageConsumerImpl {
private MyJmsTestClient jmsClient;
private Destination destination;
TestMessageConsumer(MyJmsTestClient jmsClient, Destination destination){
this.jmsClient = jmsClient;
this.destination = destination;
}
Message receive() throws JMSException{
//return message from client
}
}
There's no straight forward, you can see if there're any library that can provide you embedded JMS client feature.

Spring #Transactional does not rollback checked exceptions

I have been stuck for a while to make Spring rollback a transaction when a checked exception is thrown using #Transactional(rollbackFor). Here is my code:
The data access class:
#Repository
public class CustomerDao {
#Autowired
private SessionFactory sessionFactory;
public void willRollback() throws CheckedException {
sessionFactory.getCurrentSession().persist(new SpringCustomer(null, "roll back"));
throw new CheckedException();
}
}
Where CheckedException is just a simple checked exception:
public class CheckedException extends Exception {}
The service class CustomerService:
#Service
public class CustomerService {
#Autowired
private CustomerDao customerDao;
#Transactional(transactionManager = "hibernateTransactionManager", rollbackFor = CheckedException.class)
public void willRollback() throws CheckedException {
customerDao.willRollback();
}
}
Beans configurations:
#Configuration
public class BasicConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test_hibernate?useSSL=false");
ds.setUsername("root");
ds.setPassword("Passw0rd");
return ds;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource());
localSessionFactoryBean.setPackagesToScan("com.home.exception.checked");
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.put("hibernate.show_sql", "true");
hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
return localSessionFactoryBean;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
}
And finally, here is my main class:
#Configuration
#ComponentScan
#EnableTransactionManagement
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(Main.class);
try {
ctx.getBean(CustomerService.class).willRollback();
} catch (CheckedException e) {
e.printStackTrace();
}
ctx.close();
}
}
I've read many answers related to these questions, all of them suggesting to call the transactional method from outside the proxy itself, which I did. Regardless, the entity is always persisted in the database anyway and the transaction is not rolled back.
Any help would be appreciated.
UPDATE: As per #kavithakaran-kanapathippillai answer, I debugged the TransactionAspectSupport.completeTransactionAfterThrowing() method, and the following methods as well, and found that the rollback logic is executed. The entity still appears when querieng the db though.
So, I enabled db logging to see what queries are run, and I found the following:
2020-06-28T07:29:48.516038Z 391 Query SET autocommit=0
2020-06-28T07:29:48.520253Z 391 Query insert into spring_customer (name) values ('roll back')
2020-06-28T07:29:48.524969Z 391 Query rollback
2020-06-28T07:29:48.526026Z 391 Query SET autocommit=1
I don't know why this happens but it looks like the Spring rollback is working fine.
UPDATE2: The problem was due to my table was using the MyISAM engine (non-transactional engine). Once I changed it to InnoDB (a transactional engine), the record is not persisted anymore.
The following method is where spring checks whether to rollback when an exception is thrown. Class name is TransactionAspectSupport. You can put a break point and see whether txInfo.transactionAttribute.rollbackOn(ex) is evaluating to true
protected void completeTransactionAfterThrowing(#Nullable TransactionInfo txInfo,
Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
.....
if (txInfo.transactionAttribute != null &&
txInfo.transactionAttribute.rollbackOn(ex)) {
Reference:
TransactionAspectSupport.java

Mockito not working in spring boot service class

I am trying to run the test class below with MockBean BaaisnEvcIdMSRepository. It's connecting to the real database (I am getting an exception). Please could you explain why it is not using the mock?
Test class
#RunWith(SpringRunner.class)
#SpringBootTest
public class BaaisnEvcIdMSServiceTest {
#Autowired
BaaisnEvcIdMSService basBaaisnEvcIdMSService;
#MockBean
BaaisnEvcIdMSRepository baaisnEvcIdMSRepository;
#Test
public void getQueryEvcidServiceTest() {
BaaisnEvcIdRequest baaisnEvcIdRequest = new BaaisnEvcIdRequest();
baaisnEvcIdRequest.setLata(650);
baaisnEvcIdRequest.setProduct_type("abc");
baaisnEvcIdRequest.setSvc_type("xyz");
RowMapperServerResponse rowMapperServerResponse = new RowMapperServerResponse();
rowMapperServerResponse.setId(1);
rowMapperServerResponse.setName("sample");
Mockito.when(baaisnEvcIdMSRepository.getQueryEvcidRepository(baaisnEvcIdRequest)).thenReturn(rowMapperServerResponse);
assertEquals(rowMapperServerResponse, basBaaisnEvcIdMSService.getQueryEvcidService(baaisnEvcIdRequest));
}
}
Repository
#Repository
public class BaaisnEvcIdMSRepository {
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public RowMapperServerResponse getQueryEvcidRepository(BaaisnEvcIdRequest baaisnEvcIdRequest) {
RowMapperServerResponse rowMapperServerResponse = jdbcTemplate.queryForObject(
"select * from Master_Circuit WHERE master_ckt_id = ( select max(master_ckt_id) from master_circuit WHERE product = ? AND id_type = ?)",
new Object[]{baaisnEvcIdRequest.getProduct_type(),baaisnEvcIdRequest.getLata()}, new BaaisnRowMapper());
return rowMapperServerResponse;
}
}
exception
java.sql.SQLException: com.informix.asf.IfxASFException: Attempt to connect to database server (tdclsvi1vd002_tcp_ldap) failed.
at com.informix.jdbc.IfxSqliConnect.<init>(IfxSqliConnect.java:1691) ~[jdbc-4.10.8.1.jar:4.10.8.1]
As this is unit test, you do not need spring context. So you will need something like
#RunWith(MockitoJUnitRunner.class)
public class BaaisnEvcIdMSServiceTest {
#InjectMocks
BaaisnEvcIdMSService basBaaisnEvcIdMSService;
#Mock
BaaisnEvcIdMSRepository baaisnEvcIdMSRepository;
#Test
public void getQueryEvcidServiceTest() {
BaaisnEvcIdRequest baaisnEvcIdRequest = new BaaisnEvcIdRequest();
baaisnEvcIdRequest.setLata(650);
baaisnEvcIdRequest.setProduct_type("abc");
baaisnEvcIdRequest.setSvc_type("xyz");
RowMapperServerResponse rowMapperServerResponse = new RowMapperServerResponse();
rowMapperServerResponse.setId(1);
rowMapperServerResponse.setName("sample");
Mockito.when(baaisnEvcIdMSRepository.getQueryEvcidRepository(baaisnEvcIdRequest)).thenReturn(rowMapperServerResponse);
assertEquals(rowMapperServerResponse, basBaaisnEvcIdMSService.getQueryEvcidService(baaisnEvcIdRequest));
}
}
Assuming you indeed aim for the integration test and not for the unit test (in this case, an answer provided by #Yogesh Badke is the way to go), here are some points for consideration:
Place the breakpoint in the test and check the type of the baaisnEvcIdMSRepository. If should be some sort of proxy generated by Mockito.
If you have a proxy indeed, check the reference to the repository in BaaisnEvcIdMSService instance. It also should point on proxy and not on the real class.
Make sure BaaisnEvcIdRequest implements the equals method otherwise Mockito might not find the expectation when the real service runs the code against the repository proxy (assuming that its a proxy indeed as I've described in "2")
Provide the stacktrace of how exactly it fails with exception, it might also contain some beneficial information...

JAX-RS Exception Mapper not working in Grizzly container

Working on a Jersey web application with a team, as the project got bigger and bigger, we decided to switch from Tomcat to Grizzly to allow deploying parts of the project on different port numbers. What I've found out now, that the custom exception handling we have fails to work now, instead I always get the grizzly html page.
Example exception:
public class DataNotFoundException extends RuntimeException{
private static final long serialVersionUID = -1622261264080480479L;
public DataNotFoundException(String message) {
super(message);
System.out.println("exception constructor called"); //this prints
}
}
Mapper:
#Provider
public class DataNotFoundExceptionMapper implements ExceptionMapper<DataNotFoundException>{
public DataNotFoundExceptionMapper() {
System.out.println("mapper constructor called"); //doesnt print
}
#Override
public Response toResponse(DataNotFoundException ex) {
System.out.println("toResponse called"); //doesnt print
ErrorMessage errorMessage = new ErrorMessage(ex.getMessage(), 404, "No documentation yet.");
return Response.status(Status.NOT_FOUND)
.entity(errorMessage)
.build();
//ErrorMessage is a simple POJO with 2 string and 1 int field
}
}
I'm not sure where is the problem source, if needed I can provide more information/code. What's the problem, what can I try?
EDIT:
Main.class:
public class Main {
/**
* Main method.
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
...
List<ServerInfo> serverList = new ArrayList<ServerInfo>();
serverList.add(new ServerInfo(
"api",8450,
new ResourceConfig().registerClasses(
the.package.was.here.ApiResource.class)
));
for(ServerInfo server : serverList) {
server.start();
}
System.out.println("Press enter to exit...");
System.in.read();
for(ServerInfo server : serverList) {
server.stop();
}
}
}
EDIT2:
based on this question I've tried using this ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, "true"property, which only helped a little. I still get the html grizzly page when the exception happens, but now I see my exception (+stack trace) in the body of the page.
You're only registering one resource class for the entire application
new ResourceConfig().registerClasses(
eu.arrowhead.core.api.ApiResource.class
)
The mapper needs to be registered also
new ResourceConfig().registerClasses(
eu.arrowhead.core.api.ApiResource.class,
YourMapper.class)
)
You can also use package scanning, which will pick up all classes and automatically register them, if they are annotated with #Path or #Provider
new ResourceConfig().packages("the.packages.to.scan")