ActiveMQ Artemis, Spock, & Spring JMSMessagingTemplate - test is unstable - spring-boot

I have a Spring Boot application I'm trying to migrate to use spring-jms dependency instead of spring-activemq.
I have a few tests written with Spock. I also want to use either spring-jms-server or artemis-junit module. These tests use a JmsMessagingTemplate to send a message on a multicast address (topic), the message is then processed by some #JmsListeners on the consumers queues of these topics.
It seems that the test fails sometimes because the message sent via a JmsMessagingTemplate fails to be acknowledged or never arrives at the listeners.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>be.fgov.minfin.esbsoa.ems.ccncsi</groupId>
<artifactId>audit</artifactId>
<version>3.10.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<common-lib.version>1.8.0-SNAPSHOT</common-lib.version>
<jacoco.version>0.8.5</jacoco.version>
<sonar.tests>src/test/groovy,src/test-integration/groovy</sonar.tests>
<spock.version>2.2-M3-groovy-3.0</spock.version>
<logbook-spring-boot-starter.version>2.14.0</logbook-spring-boot-starter.version>
<jacoco.version>0.8.5</jacoco.version>
<sonar-maven-plugin.version>3.9.1.2184</sonar-maven-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<gmavenplus-plugin.version>1.13.1</gmavenplus-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>be.fgov.minfin.esbsoa.ems.ccncsi</groupId>
<artifactId>common-lib</artifactId>
<version>${common-lib.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>${logbook-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>10.0.23</version>
</dependency>
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-junit</artifactId>
<version>2.21.0</version>
</dependency>
<!-- <!– https://mvnrepository.com/artifact/org.apache.activemq/artemis-server –>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.activemq</groupId>-->
<!-- <artifactId>artemis-server</artifactId>-->
<!-- <version>2.21.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>${spock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<enableAssertions>false</enableAssertions>
</configuration>
<executions>
<execution>
<id>unit-tests</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>**/*Spec.java</include>
</includes>
<excludes>
<exclude>**/*ITSpec.java</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>integration-tests</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<!-- Never skip running the tests when the integration-test phase is invoked -->
<skip>false</skip>
<includes>
<!-- Include integration tests within integration-test phase. -->
<include>**/*ITSpec.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>${gmavenplus-plugin.version}</version>
<configuration>
<testSources>
<testSource>
<directory>src/test/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</testSource>
<testSource>
<directory>src/test-integration/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</testSource>
</testSources>
</configuration>
<executions>
<execution>
<id>unit-test-compile</id>
<goals>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>${sonar-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
In my specification, I use either
#Rule
public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
or the artemis-server dependency to start a server.
I also tried to use sleep() and #Retry but tests seem to hang in the send() method even when they are retried. In the logs, I can see that the sent message is sometimes not acknowledged. If this is the case once, retry hangs in the same spot.
You can also see my attempt to get a "fresh" server by using : start(), setReceiveDelay() and stop() on the server in the setup() and cleanup() fixtures.
AuditMessageArtemisSpec.groovy
package be.fgov.minfin.esbsoa.ems.ccncsi.audit.service
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.domain.AuditMessage
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.domain.AuditMessageHistory
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.repository.AuditMessageHistoryRepository
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.repository.AuditMessageRepository
import be.fgov.minfin.esbsoa.ems.ccncsi.common.domain.Headers
import be.fgov.minfin.esbsoa.ems.ccncsi.common.service.JmsService
import com.fasterxml.jackson.databind.ObjectMapper
import groovy.util.logging.Slf4j
import org.apache.activemq.artemis.junit.EmbeddedActiveMQResource
import org.junit.Rule
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.junit4.SpringRunner
import spock.lang.Retry
import spock.lang.Specification
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("artemis")
#ComponentScan("be.fgov.minfin.esbsoa.ems.ccncsi")
#Slf4j
class AuditMessageServiceArtemisSpec extends Specification{
static final SLEEP_TIME = 3000
#Rule
public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
#Autowired
private JmsService jmsService;
#Autowired
private AuditMessageRepository repository
#Autowired
private AuditMessageHistoryRepository historyRepository
#Value("\${ccncsi.audit.topic.toEurope}")
private String europeDestination
#Value("\${ccncsi.audit.topic.commands}")
private String commandsDestination
private ObjectMapper jsonMapper = new ObjectMapper()
//def setup() {
// server.start()
// server.setDefaultReceiveTimeout(SLEEP_TIME)
//}
#Retry(delay = 10000)
def 'Send a valid message to Europe'() {
when:
def msg = send(europeDestination,"tests/message1.json")
then: "Verify if message is inserted in table AUDIT_MESSAGE"
sleep(SLEEP_TIME)
List<AuditMessage> messages = repository.findAll().collect()
messages.size() == 1
AuditMessage auditMessage = messages.get(0)
auditMessage.id != null
auditMessage.messageId == msg.headers.get(Headers.MESSAGE_ID)
auditMessage.reference == null
auditMessage.content != null
auditMessage.content.contentType == "text/plain"
new String(Base64.decoder.decode(auditMessage.content.content)) == "Here is the body of message1"
auditMessage.contentStored
auditMessage.messageTimestamp != null
auditMessage.creationDate != null
check(auditMessage, msg, Headers.MESSAGE_ID, Headers.APPLICATION, Headers.CONTENT_TYPE, Headers.COUNTRY_CODE, Headers.QUEUE_BASE_NAME, Headers.MESSAGE_TYPE)
and: "Check method findByMessageIdOrderByCreation"
List<AuditMessage> messagesByMessageId = repository.findByMessageIdOrderByCreationDate(auditMessage.getMessageId())
messagesByMessageId.size() == 1
messagesByMessageId.get(0).id == auditMessage.id
and: "Check if a status event is sent"
sleep(SLEEP_TIME)
List<AuditMessageHistory> histories = historyRepository.findAll().collect()
histories.size() == 1
}
#Retry(delay = 10000)
def 'Send a reply message from Europe - with correlationId'() {
when:
def msg = send(europeDestination,"tests/message2.json")
sleep(SLEEP_TIME)
then: "Verify if message is inserted in table AUDIT_MESSAGE"
List<AuditMessage> messagesByMessageId = repository.findByMessageIdOrderByCreationDate(msg.headers.get(Headers.MESSAGE_ID))
messagesByMessageId.size() == 1
messagesByMessageId.get(0).reference != null
}
#Retry(delay = 10000)
def 'Send message with body null'() {
when:
def msg = send(europeDestination,"tests/message5.json")
sleep(SLEEP_TIME)
then: "Verify if message is inserted in table AUDIT_MESSAGE and contentStored is false"
List<AuditMessage> messagesByMessageId = repository.findByMessageIdOrderByCreationDate(msg.headers.get(Headers.MESSAGE_ID))
messagesByMessageId.size() == 1
!messagesByMessageId.get(0).contentStored
}
#Retry(delay = 10000)
def 'Bad message3.json -> No inserts'() {
when:
def msg = send(europeDestination,"tests/message3.json")
sleep(SLEEP_TIME)
then: "Verify if message is not inserted in table AUDIT_MESSAGE"
List<AuditMessage> messagesByMessageId = repository.findByMessageIdOrderByCreationDate(msg.headers.get(Headers.MESSAGE_ID))
messagesByMessageId.size() == 0
List<AuditMessageHistory> messageHistories = repository.findByMessageIdOrderByCreationDate(msg.headers.get(Headers.MESSAGE_ID))
messageHistories.size() == 0
}
//def cleanup() {
// server.stop()
// sleep(SLEEP_TIME)
//}
def get(String path) {
URL url = this.getClass().getClassLoader().getResource(path)
return jsonMapper.readValue(url, AuditTestMessage.class)
}
def send(String destination, String path) {
log.error("sending message from file: {} to {}", path.toString(), destination)
AuditTestMessage msg = get(path)
jmsService.send(destination, msg.getHeaders(), msg.getBody())
return msg
}
def check(AuditMessage msg1, AuditTestMessage msg2, String... keys) {
for (String key : keys) {
if (msg2.getHeaders().get(key) != msg1.getHeaders().get(key)) {
log.error("Header ["+key+"] : "+ msg1.getHeaders().get(key) + " != " + msg2.getHeaders().get(key))
return false
}
}
return true
}
}
JMSConfig.java
Below you can see an attempt at setting subdomain to true on the JMSFactory as I'm sending the messages to a topic. This did not change any behavior.
package be.fgov.minfin.esbsoa.ems.ccncsi.audit.config;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.service.JmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import org.springframework.lang.Nullable;
import org.springframework.messaging.support.MessageBuilder;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import java.util.Map;
#Configuration
#EnableJms
public class JMSConfig {
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
//factory.setPubSubDomain(true);
// You could still override some of Boot's default if necessary.
return factory;
}
#Bean
JmsService jmsService(#Autowired JmsMessagingTemplate jmsMessagingTemplate) {
return new JmsService() {
#Override
public void send(String destination, Object payload) {
jmsMessagingTemplate.send(destination, MessageBuilder.withPayload(payload).build());
}
#Override
public void send(String destination, Map<String, Object> headers, Object payload) {
if (headers == null) send(destination, payload);
else jmsMessagingTemplate.send(destination, MessageBuilder.withPayload(payload).copyHeaders(headers).build());
}
};
}
}
MessageListener.java
package be.fgov.minfin.esbsoa.ems.ccncsi.audit.listener;
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.domain.AuditMessage;
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.service.AuditMessageHistoryService;
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.service.AuditMessageMapper;
import be.fgov.minfin.esbsoa.ems.ccncsi.audit.service.AuditMessageService;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.domain.DestinationType;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.domain.command.Command;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.domain.event.StatusEvent;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.domain.event.StatusType;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.service.JsonService;
import be.fgov.minfin.esbsoa.ems.ccncsi.common.service.StatusEventService;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.support.JmsHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import javax.transaction.Transactional;
import java.io.IOException;
#Component
#Slf4j
public class MessageListener {
private final AuditMessageService service;
private final AuditMessageMapper mapper;
private final StatusEventService statusEventService;
private final JsonService jsonService;
private final AuditMessageHistoryService historyService;
private final JmsMessagingTemplate jmsMessagingTemplate;
#Value("${ccncsi.audit.queue.fromEuropeError:Consumer.ccncsiaudit.VirtualTopic.ccncsi.fromEurope.rme}")
private String fromEuropeError;
#Value("${ccncsi.audit.queue.toEuropeError:Consumer.ccncsiaudit.VirtualTopic.ccncsi.toEurope.rme}")
private String toEuropeError;
#Autowired
public MessageListener(AuditMessageService service, AuditMessageMapper mapper, StatusEventService statusEventService,
be.fgov.minfin.esbsoa.ems.ccncsi.common.service.JsonService jsonService, AuditMessageHistoryService historyService,
JmsMessagingTemplate jmsMessagingTemplate) {
this.mapper = mapper;
this.service = service;
this.statusEventService = statusEventService;
this.jsonService = jsonService;
this.historyService = historyService;
this.jmsMessagingTemplate = jmsMessagingTemplate;
}
#JmsListener(destination = "${ccncsi.audit.queue.toEurope:Consumer.ccncsiaudit.VirtualTopic.ccncsi.toEurope}", concurrency = "${ccncsi.audit.queue.concurrency:1-10}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onMessageToEurope(Message<?> message) {
save(message, DestinationType.TO_EUROPE);
}
#JmsListener(destination = "${ccncsi.audit.queue.fromEurope:Consumer.ccncsiaudit.VirtualTopic.ccncsi.fromEurope}", concurrency = "${ccncsi.audit.queue.concurrency:1-10}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onMessageFromEurope(Message<?> message) {
save(message, DestinationType.FROM_EUROPE);
}
private void save(Message<?> message, DestinationType destination) {
AuditMessage auditMessage = service.save(mapper.map(message, destination));
statusEventService.notify(message.getHeaders(), auditMessage.getId(), StatusType.AUDIT_STORE_SUCCESS);
}
#JmsListener(destination = "${ccncsi.audit.queue.events:Consumer.ccncsiaudit.VirtualTopic.ccncsi.events}", concurrency = "${ccncsi.audit.queue.concurrency:1-10}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onEventMessage(Message<?> event) throws IOException {
StatusEvent statusEvent = jsonService.fromString((String) event.getPayload(), StatusEvent.class);
historyService.save(statusEvent);
}
#JmsListener(destination = "${ccncsi.audit.queue.commands:Consumer.ccncsiaudit.VirtualTopic.ccncsi.commands}", concurrency = "${ccncsi.audit.queue.concurrency:1-10}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onCommandMessage(Message<?> command) throws Exception {
JsonNode jsonCommand = jsonService.fromString((String) command.getPayload());
service.execute((Command) jsonService.fromJSonNode(jsonCommand, Class.forName(jsonCommand.get("name").textValue())));
}
#JmsListener(destination = "DLQ.${ccncsi.audit.queue.toEurope:Consumer.ccncsiaudit.VirtualTopic.ccncsi.toEurope}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onErrorToEurope(Message<?> message) {
statusEventService.notify(message.getHeaders(), message.getHeaders().get(JmsHeaders.MESSAGE_ID), StatusType.AUDIT_STORE_FAILED);
jmsMessagingTemplate.send(toEuropeError, message);
}
#JmsListener(destination = "DLQ.${ccncsi.audit.queue.fromEurope:Consumer.ccncsiaudit.VirtualTopic.ccncsi.fromEurope}")
#Transactional(value = Transactional.TxType.REQUIRED)
public void onErrorFromEurope(Message<?> message) {
statusEventService.notify(message.getHeaders(), message.getHeaders().get(JmsHeaders.MESSAGE_ID), StatusType.AUDIT_STORE_FAILED);
jmsMessagingTemplate.send(fromEuropeError, message);
}
}
Below you can see that I modified the addresses to the artemis format. The specification sends messages to VirtualTopic.ccncsi.toEurope (topic) and are received on the consumer queues of this address.
application.yml (relevant section)
ccncsi:
common:
statusEventDestination: VirtualTopic.ccncsi.events
audit:
#Maximum size of content (in Kilobytes)
max-size-content-storage: 5000
topic:
toEurope: VirtualTopic.ccncsi.toEurope
fromEurope: VirtualTopic.ccncsi.fromEurope
commands: VirtualTopic.ccncsi.commands
queue:
toEurope: VirtualTopic.ccncsi.toEurope::Consumer.ccncsiaudit.VirtualTopic.ccncsi.toEurope
fromEurope: VirtualTopic.ccncsi.fromEurope::Consumer.ccncsiaudit.VirtualTopic.ccncsi.fromEurope
events: VirtualTopic.ccncsi.events::Consumer.ccncsiaudit.VirtualTopic.ccncsi.events
commands: VirtualTopic.ccncsi.commands::Consumer.ccncsiaudit.VirtualTopic.ccncsi.commands
concurrency: 1-30
application-junit.yml
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: create
datasource:
url: jdbc:h2:mem:testdb;NON_KEYWORDS=KEY,VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password: password
driverClassName: org.h2.Driver
jms:
pub-sub-domain: true
template:
default-destination: VirtualTopic.ccncsi.toEurope
# artemis:
# embedded:
# enabled: true
# persistent: true
# mode: embedded
# broker-url: vm://0?virtualTopicConsumerWildcards=Consumer.*.%3E%3B2
Can anyone tell me what I am doing wrong ?

Related

Springboot app deployed in CloudFoundry - Get and Post operation on db fail

I am building a sample Spring application that will expose a REST
API to get and post data to a table in a database. Building the basic stuff.
I am using PostgreSQL for the data source in Cloud Foundry.
The GET API which returns a string works fine. The API which does POST returns 404 Not Found. The API which returns the entries in the table throws an exception.
Type Exception Report
Message Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException
Description:
The server encountered an unexpected condition that prevented it from fulfilling the request.
Exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: syntax error at or near "GROUP"
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#Configuration
#EnableJpaRepositories(basePackageClasses =
CustomerFeedbackRepository.class)
#Profile("cloud")
public class CloudDatabaseConfig extends AbstractCloudConfig {
#Bean
public DataSource dataSource() {
List<String> dataSourceNames =
Arrays.asList("BasicDbcpPooledDataSourceCreator","TomcatJdbcPooledDataSourceCreator","HikariCpPooledDataSourceCreator","TomcatDbcpPooledDataSourceCreator");
DataSourceConfig dbConfig = new DataSourceConfig(dataSourceNames);
return connectionFactory().dataSource(dbConfig);
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
return EntityManagerFactoryProvider.get(dataSource, CustomerFeedback.class.getPackage().getName());
}
#Bean(name = "transactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
#PostMapping("/capturecf")
#RequestMapping(value ="CustomerFeedback", method = RequestMethod.POST)
public CustomerFeedback addFeedback(#RequestBody CustomerFeedback custfeedback)
{
return customerfeedbackrepo.save(custfeedback);
}
#PostMapping("/captureua")
#RequestMapping(value = "UsageActivity", method = RequestMethod.POST)
public UsageActivity addUsageTracking(#Valid #RequestBody UsageActivity usageActivity)
{
return usageactivityrepository.save(usageActivity);
}
#GetMapping("/usageactivity")
public List<UsageActivity> getAllNotes() {
return usageactivityrepository.findAll();`enter code here`
}
<dependencies>
<!-- APIs for servlets and injection -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Spring Framework and Spring WebMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Logging library -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>com.sap.hcp.cf.logging</groupId>
<artifactId>cf-java-logging-support-logback</artifactId>
<version>${sap.logging.version}</version>
</dependency>
<dependency>
<groupId>com.sap.hcp.cf.logging</groupId>
<artifactId>cf-java-logging-support-servlet</artifactId>
<version>${sap.logging.version}</version>
</dependency>
<!-- JSON conversion -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
<!-- Actuator for adding management endpoints -->
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
<!-- Bean validation (#NotNull etc.) -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!-- MethodValidationPostProcessor relies on Expression Language -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.1-b04</version>
</dependency>
<!-- Spring Cloud Connector -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-spring-service-connector</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-cloudfoundry-connector</artifactId>
<version>1.2.1.RELEASE</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.2.RELEASE</version>
<exclusions>
<exclusion>
<!-- We need spring-core 4.2 or later, but spring-data includes 4.1.9 -->
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- EclipseLink as JPA implementation -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.2</version>
</dependency>
<!-- PostgreSQL database implementations -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1206-jdbc41</version>
<scope>runtime</scope>
</dependency>
<!-- connection pooling -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
<scope>runtime</scope>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- Use MockMvcResultMatchers.jsonPath to assert the JSON body -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<!-- H2 (in-memory) database implementation -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.184</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>customerconnect</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<!-- Provides the application at http://localhost:8080/ using an embedded
Tomcat server with a pre-configured environment referencing the SAP proxy -->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>${maven.tomcat.port}</port>
<path>/</path>
<systemProperties>
<http.proxyHost>${http.proxyHost}</http.proxyHost>
<http.proxyPort>${http.proxyPort}</http.proxyPort>
</systemProperties>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>findbugs</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.5</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>pmd</goal>
<goal>cpd</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
</plugins>
</reporting>
</project>
package com.sap.customerconnect.ads.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.sap.customerconnect.ads.models.UsageActivity;
import com.sap.customerconnect.ads.models.UsageActivityPK;
#Component
#Repository
public interface UsageActivityRepository extends JpaRepository<UsageActivity, UsageActivityPK> {
}
package com.sap.customerconnect.ads.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.sap.customerconnect.ads.models.CustomerFeedback;
import com.sap.customerconnect.ads.models.CustomerFeedbackPK;
#Component
#Repository
public interface CustomerFeedbackRepository extends JpaRepository<CustomerFeedback, CustomerFeedbackPK>{
}
package com.sap.customerconnect.ads.models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
#IdClass(UsageActivityPK.class)
#Entity
#Table(name = "UsageActivity")
public class UsageActivity {
#Id
#Column(name = "PRODUCT_ID")
private String ProductId;
#Id
#Column(name = "CUSTOMER_ID")
private String CustomerId;
#Id
#Column(name = "SCREEN_ID")
private String ScreenId;
#Column(name = "GROUP")
private String Group;
#Column(name = "ACTION")
private String Action;
#Column(name = "DESCRIPTION")
private String Description;
#Column(name = "COUNT")
private Integer Count;
public UsageActivity() {
}
public String getProductId() {
return ProductId;
}
public void setProductId(String productId) {
ProductId = productId;
}
public String getCustomerId() {
return CustomerId;
}
public void setCustomerId(String customerId) {
CustomerId = customerId;
}
public String getScreenId() {
return ScreenId;
}
public void setScreenId(String screenId) {
ScreenId = screenId;
}
public String getGroup() {
return Group;
}
public void setGroup(String group) {
Group = group;
}
public String getAction() {
return Action;
}
public void setAction(String action) {
Action = action;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public Integer getCount() {
return Count;
}
public void setCount(Integer count) {
Count = count;
}
public UsageActivity(String productId, String customerId, String screenId, String group, String action,
String description, Integer count) {
super();
ProductId = productId;
CustomerId = customerId;
ScreenId = screenId;
Group = group;
Action = action;
Description = description;
Count = count;
}
}
package com.sap.customerconnect.ads.models;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class UsageActivityPK implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "PRODUCT_ID")
private String ProductId;
#Column(name = "CUSTOMER_ID")
private String CustomerId;
#Column(name = "SCREEN_ID")
private String ScreenId;
}
The POST and GET operations on the repository does not work.

maven project using rest controller and gave a basic request and gives 404. url : http://localhost:8080/Spring4MVCHelloWorldRestServiceDemo/testrest

I created a maven project using rest controller and gave a basic request but it is not hitting the method and gives 404.i am new to the rest controller. So it would be great if someone try to narrow down the issue.
the url : http://localhost:8080/Spring4MVCHelloWorldRestServiceDemo/testrest
HelloController
package com.fis.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloController {
#RequestMapping(value="/testrest", method = RequestMethod.GET)
public String welcome() {//Welcome page, non-rest
System.out.println("Test++++++++++++++");
return "Welcome to RestTemplate Example.";
}
/* #RequestMapping("/hello/{player}")
public Message message(#PathVariable String player) {//REST Endpoint.
Message msg = new Message(player, "Hello " + player);
return msg;
}*/
}
HelloInitialization
package com.fis.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class HelloInitialization extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HelloConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
HelloConfiguration
package com.fis.configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.fis.controller"})
public class HelloConfiguration {
}
http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.websystique.springmvc</groupId>
<artifactId>Spring4MVCHelloWorldRestServiceDemo</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<name>Spring4MVCHelloWorldRestServiceDemo Maven Webapp</name>
<properties>
<springframework.version>4.3.0.RELEASE</springframework.version>
<jackson.library>2.7.5</jackson.library>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.library}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.library}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<warName>Spring4MVCHelloWorldRestServiceDemo</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<finalName>Spring4MVCHelloWorldRestServiceDemo</finalName>
</build>

Spring Boot Failure due to Transaction Management

I am currently developing an application using spring boot with cassandra as the database.
I have written a class which initializes my cassandra cluster. The problem starts as soon as I start using #Transactional in my DAO Layer Query Methods. System doesn't allow me to use them at a below error message is thrown at runtime -
An exception has occured in method getMdoBean with msg: No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available.
I don't understand what is going wrong. My app works fine without spring boot with no issues related to Transaction Management.
I tried adding JPA Support along with H2 Database and it resolved my problem. I did my homework and read about H2 Database and its in-memory data storage mechanism. I am failing to understand how is TransactionManagement issue is getting fixed? Is it because of H2 Database drivers which are taking care of it?
Secondly, I don't need H2 Database hence this solution does not seems to be good for me. Backend is Cassandra for my application. Any leads would be helpful. Thanks!
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shc.sov</groupId>
<artifactId>SOV</artifactId>
<version>4.4.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SOV</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<org.springframework.version>4.1.4.RELEASE</org.springframework.version>
<jersey.version>1.14</jersey.version>
<maven.antrun.plugin.version>1.8</maven.antrun.plugin.version>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<id>shc-central</id>
<name>Sears Libraries</name>
<url>http://obuartifactoryvip.prod.ch3.s.com/artifactory/libs-release</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>shc-snapshots</id>
<name>Sears Snapshot Libraries</name>
<url>http://obuartifactoryvip.prod.ch3.s.com/artifactory/libs-snapshot</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<finalName>dpsserver</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>prod/*.*</exclude>
<exclude>qa/*.*</exclude>
<exclude>stress/*.*</exclude>
<exclude>dev/*.*</exclude>
<exclude>dev-spring-boot</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>config</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptor>config.xml</descriptor>
<attach>true</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<!-- Always download and attach dependencies source code -->
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
<!-- Avoid type mvn eclipse:eclipse -Dwtpversion=2.0 -->
<wtpversion>2.0</wtpversion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Class-Path>config/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.3.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Core utilities used by other modules. Define this if you use Spring
Utility APIs (org.springframework.core.*/org.springframework.util.*) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- In memory database used by spring-boot -->
<!-- <dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency> -->
<dependency>
<groupId>com.searshc.dce.persistence</groupId>
<artifactId>DcePersistence</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<!-- <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency> -->
<!-- https://mvnrepository.com/artifact/log4j/apache-log4j-extras -->
<dependency>
<groupId>log4j</groupId>
<artifactId>apache-log4j-extras</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<!-- <dependency> <groupId>javax.ws.rs</groupId> <artifactId>jsr311-api</artifactId>
<version>1.1.1</version> </dependency> -->
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<artifactId>spring-aop</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.7-b41</version>
</dependency>
<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId>
<version>2.5</version> <scope>provided</scope> </dependency> -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>1.7.2</version>
</dependency>
<!-- Unit test level dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<!-- <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId>
<version>1.9.5</version> <scope>test</scope> </dependency> -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>1.4.6.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Compilation Level Dependencies -->
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>${maven.antrun.plugin.version}</version>
<scope>compile</scope>
</dependency>
<!-- DATASTAX -->
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>2.1.4</version>
</dependency>
<!-- DATASTAX -->
</dependencies>
</project>
Cassandra Configuration Class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.cassandra.config.CassandraClusterFactoryBean;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import com.datastax.driver.core.PlainTextAuthProvider;
#Configuration
#ImportResource("application-context.xml")
#PropertySource(value = { "classpath:cassandra.properties" })
#EnableCassandraRepositories(basePackages = {"com.spring.sample"})
public class CassandraDsConfig {
#Autowired
private Environment env;
#Bean
public CassandraClusterFactoryBean configureCassandraCluster() {
CassandraClusterFactoryBean clusterFactory = new CassandraClusterFactoryBean();
clusterFactory.setContactPoints(env.getProperty("cassandra.Newcontactpoints"));
clusterFactory.setPort(Integer.parseInt(env.getProperty("cassandra.Newport")));
PlainTextAuthProvider plainTextAuthProvider = new PlainTextAuthProvider(env.getProperty("cassandra.username"),
env.getProperty("cassandra.password"));
clusterFactory.setAuthProvider(plainTextAuthProvider);
return clusterFactory;
}
#Bean
public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}
#Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
#Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(configureCassandraCluster().getObject());
session.setKeyspaceName(env.getProperty("cassandra.Newkeyspace"));
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
#Primary
#Bean("cassandraNewTemplate")
public CassandraOperations cassandraNewTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
Spring Boot Main Class
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
//import org.springframework.context.annotation.PropertySource;
import org.springframework.boot.Banner;
/**
* #author bnarula
*
*/
#SpringBootApplication
#ImportResource("application-context.xml")
#Import(CassandraDsConfig.class)
#PropertySource("dps.properties")
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
#ComponentScan(basePackages = "com.shc.marketplace.ias")
public class DPSMainModule extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return configureApplication(builder);
}
public static void main(String[] args) {
configureApplication(new SpringApplicationBuilder()).run(args);
}
private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
return builder.sources(DPSMainModule.class).bannerMode(Banner.Mode.OFF);
}
}
DAO Layer Class for Caching -
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.transaction.annotation.Transactional;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.searshc.dce.persistence.DcePersistence.dao.beans.FreightAreaBean;
import com.searshc.dce.persistence.DcePersistence.dao.beans.FreightAreaPOJO;
import com.shc.scinventory.dps.server.dao.CacheBuilderDAO;
import com.shc.scinventory.dps.server.model.StoretoRRCPOJO;
import com.shc.scinventory.dps.server.model.ZiptoWarehousePOJO;
public class CacheBuilderDAOImpl implements CacheBuilderDAO {
private static Logger logger = Logger.getLogger(CacheBuilderDAOImpl.class);
private Map<String, String> storeToRRCMap = new HashMap<String, String>();
private Map<String, String> ziptoWarehouseMap = new HashMap<String, String>();
private Map<String, List<FreightAreaBean>> zipToFaMap = new HashMap<String, List<FreightAreaBean>>();
List<StoretoRRCPOJO> storeToRRCList = new ArrayList<StoretoRRCPOJO>();
public List<StoretoRRCPOJO> getStoreToRRCList() {
return storeToRRCList;
}
public void setStoreToRRCList(List<StoretoRRCPOJO> storeToRRCList) {
this.storeToRRCList = storeToRRCList;
for (StoretoRRCPOJO storetoRRCBean : storeToRRCList) {
storeToRRCMap.put(storetoRRCBean.getStore(), storetoRRCBean.getRrc());
}
}
#Autowired
private CassandraOperations cassandraOperations;
private String keyspace;
#Override
public void initStatements() {
logger.debug("CacheBuilderDAOImpl : Inside method init");
if (cassandraOperations == null) {
logger.error("Cassandra not available");
} else {
List<ZiptoWarehousePOJO> ziptoWarehouseList = getZiptoWarehouseMapping();
List<StoretoRRCPOJO> storetoRRCList = getStoretoRRCMapping();
for (ZiptoWarehousePOJO ziptoWarehouseBean : ziptoWarehouseList) {
ziptoWarehouseMap.put(ziptoWarehouseBean.getDestinationZip(), ziptoWarehouseBean.getDcUnit());
}
setStoreToRRCList(storetoRRCList);
refreshZipToFaMapping();
}
}
public void refreshZipToFaMapping() {
zipToFaMap = getZipToFAMapping();
}
#Transactional
public Map<String, List<FreightAreaBean>> getZipToFAMapping() {
logger.debug("Inside method getZipToFAMapping");
Map<String, List<FreightAreaBean>> result = new HashMap<String, List<FreightAreaBean>>();
try {
Select select = QueryBuilder.select().all().from("capacity", "freight_area");
List<FreightAreaPOJO> queryResult = cassandraOperations.select(select, FreightAreaPOJO.class);
for(FreightAreaPOJO faPOJO : queryResult) {
String zip = faPOJO.getGeocode_no();
if(!result.containsKey(zip)) {
result.put(zip, new LinkedList<FreightAreaBean>());
}
FreightAreaBean faBean = new FreightAreaBean();
BeanUtils.copyProperties(faPOJO, faBean);
result.get(zip).add(faBean);
}
} catch (Exception e) {
logger.error("getZipToFAMapping Error while fetch data from DB: " + e.getMessage());
e.printStackTrace();
}
logger.debug("Exiting method getZipToFAMapping");
return result;
}
public List<ZiptoWarehousePOJO> getZiptoWarehouseMapping() {
logger.debug("Inside method getZiptoWarehouseMapping");
List<ZiptoWarehousePOJO> result = null;
try {
Select select = QueryBuilder.select().all().from(getKeyspace(), "ziptowarehouse");
result = cassandraOperations.select(select, ZiptoWarehousePOJO.class);
} catch (Exception e) {
logger.error("getZiptoWarehouseMapping Error while fetch data from DB: " + e.getMessage());
}
logger.debug("Exiting method getZiptoWarehouseMapping");
return result;
}
public List<StoretoRRCPOJO> getStoretoRRCMapping() {
logger.debug("Inside method getStoretoRRCMapping");
List<StoretoRRCPOJO> result = null;
try {
Select select = QueryBuilder.select().all().from(getKeyspace(), "storetorrc");
result = cassandraOperations.select(select, StoretoRRCPOJO.class);
} catch (Exception e) {
logger.error("getStoretoRRCMapping Error while fetch data from DB: " + e.getMessage());
}
logger.debug("Exiting method getStoretoRRCMapping");
return result;
}
public String getKeyspace() {
return keyspace;
}
public void setKeyspace(String keyspace) {
this.keyspace = keyspace;
}
public Map<String, String> getStoreToRRCMap() {
return storeToRRCMap;
}
public void setStoreToRRCMap(Map<String, String> storeToRRCMap) {
this.storeToRRCMap = storeToRRCMap;
}
public Map<String, String> getZipToWarehouseMap() {
return ziptoWarehouseMap;
}
public void setZiptoWarehouseMap(Map<String, String> ziptoWarehouseMap) {
this.ziptoWarehouseMap = ziptoWarehouseMap;
}
public Map<String, List<FreightAreaBean>> getZipToFaMap() {
return zipToFaMap;
}
public void setZipToFaMap(Map<String, List<FreightAreaBean>> zipToFaMap) {
this.zipToFaMap = zipToFaMap;
}
}
If I use #Transactional in the above class at method level, it doesn't allow without adding H2 Support for JPA. It works fine after putting up below lines of code in POM.
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
I guess the reason is you excluded HibernateJpaAutoConfiguration, is there any reason to do so, otherwise I will suggest you to add it back, maybe also add #EnableTransactionManagement to your config class.

ContextConfiguration does not seem to load my beans for TestNg testcase

I am new to TestNg. I am trying to test one sample hello world program.
Following is my project structure
Source Package
com.mycompany.mavenproject1 =>HelloWorld.java
Test Package
com.test => NewTestConfig.java & NewTestNGTest.java
Helloworld.java
package com.mycompany.mavenproject1;
public class HelloWorld {
String msg = "test";
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
NewTestConfig.java
package com.test;
import com.mycompany.mavenproject1.HelloWorld;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class NewTestConfig {
#Bean
public HelloWorld helloWorldBean() {
HelloWorld hw = new HelloWorld();
return hw;
}
}
NewTestNGTest.java
package com.test;
import com.mycompany.mavenproject1.HelloWorld;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.springframework.test.context.ContextConfiguration;
#Test
#ContextConfiguration(classes={ NewTestConfig.class })
public class NewTestNGTest {
#Autowired
HelloWorld hw ;
#Test
public void exampleOfTestNgMaven() {
String s = hw.getMsg();
System.out.println("This is TestNG-Maven Example" + s);
}
#BeforeClass
public static void setUpClass() throws Exception {
}
#AfterClass
public static void tearDownClass() throws Exception {
}
#BeforeMethod
public void setUpMethod() throws Exception {
}
#AfterMethod
public void tearDownMethod() throws Exception {
}
}
My pom.xml looks like below:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>mavenproject1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mavenproject1</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
When I try to run the test I get NullpointerException (at hw.getMsg();)
Error stack:
Test set: com.test.NewTestNGTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.209 sec <<< FAILURE!
exampleOfTestNgMaven(com.test.NewTestNGTest) Time elapsed: 0.003 sec <<< FAILURE!
java.lang.NullPointerException
at com.test.NewTestNGTest.exampleOfTestNgMaven(NewTestNGTest.java:25)
I tried to run test in debug mode, I always get HelloWorld bean as null. So eventually test fails due to NullPointerException. I tried many other variations such as instead of config class tried using applicationContext.xml but my bean never gets injected.
For last 2 days I am struggling to make simple test pass but unable to figure out what's going wrong. Why my context is not getting loaded for test?
Any help is greatly appreciated.
Thanks
Manisha

Bean type not found when using Spring aspect and java config

I added an aspect to a working Spring+Wicket application to log thrown exceptions, and now I get the following error whenever I load the Report page:
ERROR | 2013-12-09 08:42:06,149 | qtp1559334851-16 | DefaultExceptionMapper:123 - Unexpected error occurred
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public org.jonblack.ReportPage() throws java.lang.Exception'. An exception has been thrown during construction!
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:194)
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:67)
...
Caused by: java.lang.IllegalStateException: bean of type [org.jonblack.ReportController] not found
at org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getBeanNameOfClass(AnnotProxyFieldValueFactory.java:236)
at org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getBeanName(AnnotProxyFieldValueFactory.java:179)
...
I'm using java configuration for the project, so there is no applicationContext.xml. All configuration is done via annotations, the bulk of which are in AppConfig.java.
All the code for my application is shown below. I've left out the HTML templates and HomePage as they aren't integral to the problem.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.jonblack</groupId>
<artifactId>sw-p2</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<!-- TODO project name -->
<name>sw-p2</name>
<description></description>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<aspectj.version>1.7.4</aspectj.version>
<spring.version>3.2.4.RELEASE</spring.version>
<wicket.version>6.11.0</wicket.version>
<jetty.version>7.6.3.v20120416</jetty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- WICKET DEPENDENCIES -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-core</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-extensions</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.wicketstuff</groupId>
<artifactId>wicketstuff-annotation</artifactId>
<version>${wicket.version}</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
<version>${wicket.version}</version>
</dependency>
<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- LOGGING DEPENDENCIES - LOG4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- JUNIT DEPENDENCY FOR TESTING -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!-- JETTY DEPENDENCIES FOR TESTING -->
<dependency>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all-server</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<filtering>false</filtering>
<directory>src/test/resources</directory>
</testResource>
<testResource>
<filtering>false</filtering>
<directory>src/test/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8080</port>
<maxIdleTime>3600000</maxIdleTime>
</connector>
<connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector">
<port>8443</port>
<maxIdleTime>3600000</maxIdleTime>
<keystore>${project.build.directory}/test-classes/keystore</keystore>
<password>wicket</password>
<keyPassword>wicket</keyPassword>
</connector>
</connectors>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
</plugins>
</build>
</project>
AppConfig.java
package org.jonblack;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
//import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
#ComponentScan("org.jonblack")
#EnableAsync
#EnableAspectJAutoProxy()
public class AppConfig {
private static final Logger log = LoggerFactory.getLogger(AppConfig.class);
#Bean
public ReportController reportController() {
log.info("Getting ReportController");
return new ReportController();
}
#Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(5);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
return pool;
}
#Bean
public ExceptionLoggingAspect exceptionLoggingAspect() {
return new ExceptionLoggingAspect();
}
#Bean
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator aop = new AnnotationAwareAspectJAutoProxyCreator();
return aop;
}
}
ExceptionLoggingAspect.java
package org.jonblack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class ExceptionLoggingAspect {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionLoggingAspect.class);
#AfterThrowing(pointcut="execution(* org.jonblack.ReportController.getReportData(..))", throwing="ex")
public void afterThrowing(Throwable ex) {
LOG.error(ex.getMessage());
}
}
ReportController.java
package org.jonblack;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Controller;
#Controller
public class ReportController {
private static final Logger log = LoggerFactory.getLogger(ReportController.class);
#Autowired
private ThreadPoolTaskExecutor taskExecutor;
#Async
public Future<String> getReportData() throws Exception {
log.info("Entered into getReportData()");
try {
log.info("Throwing an exception");
throw new Exception("Something went wrong");
} catch(Exception ex) {
log.error("In catch block: {}", ex.getMessage());
}
final Future<String> result = taskExecutor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return "not a fancy result";
}
});
log.info("Returning from getReportData()");
return result;
}
}
ReportPage.java
package org.jonblack;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.wicketstuff.annotation.mount.MountPath;
#MountPath("report")
public class ReportPage extends WebPage {
private static final Logger log = LoggerFactory.getLogger(ReportPage.class);
#SpringBean
ReportController reportController;
public ReportPage() throws Exception {
log.info("Starting ReportPage");
reportController.getReportData();
}
}
WicketApplication.java
package org.jonblack;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.wicketstuff.annotation.scan.AnnotatedMountScanner;
public class WicketApplication extends WebApplication
{
#Override
public Class<? extends WebPage> getHomePage()
{
return HomePage.class;
}
#Override
public void init()
{
super.init();
// Spring
getComponentInstantiationListeners().add(
new SpringComponentInjector(this));
// Annotation-driven page mounting
new AnnotatedMountScanner().scanPackage("org.jonblack").mount(this);
}
}
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>sw-p2</display-name>
<!-- Configuration loading -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.jonblack.AppConfig</param-value>
</context-param>
<!-- Spring -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Wicket -->
<filter>
<filter-name>wicket.sw-p2</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>org.jonblack.WicketApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicket.sw-p2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
I've followed the Spring reference for Aspects but it's very thin on the ground when it comes to java configurations (and I do find the reference to be quite hard to follow).
I've also done the obligatory DuckDuckGo search and found only references to XML configurations.
On stackoverflow itself I have found this post which explains the same problem, but the cause in that instance was an incorrect annotation and incorrectly named applicationContext.xml file: neither of these helped resolve my situation. I tried using #Autowired instead of #SpringBean, and got the same NullPointerException. Given that the linked post resolved it without this change, I assume this isn't the right path to take.
The problem lies in your configuration.
#Bean
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator aop = new AnnotationAwareAspectJAutoProxyCreator();
return aop;
}
This bean leads to creation of a proxy of a proxy. The #EnableAspectJAutoProxy annotation already registers an AutoProxyCreator and due to the existence of multiple, different instances, this will lead to proxy duplication.
Next to that the additional declaration of your aspect might lead to 2 aspects being instantiated.
#Bean
public ExceptionLoggingAspect exceptionLoggingAspect() {
return new ExceptionLoggingAspect();
}
Your #Aspect is also an #Component and as such will be detected by the #ComponentScan functionality.
Basically removing both beans should fix your problem.
public Future<String> getReportData() throws Exception {
log.info("Entered into getReportData()");
try {
log.info("Throwing an exception");
throw new Exception("Something went wrong");
} catch(Exception ex) { // This catch blocks swallows the exception
log.error("In catch block: {}", ex.getMessage());
}
}
Next to your configuration problems, you also have a problem with your code. Basically your aspect is useless. You have a try/catch block in your code which swallows the Exception. This swallowing leads to a situation where your aspect never sees the exception and will never trigger. From your aspects point of view the exception never happened.
Either don't catch and simply let the Exception bubble up the stack or rethrow the Exception.

Resources