How to return serialized object using MappingJackson2HttpMessageConverter - spring

I am learning Spring Framework and the first goal for me is to return an Version object using a built in serializer.
public class Version {
private int build;
private String releaseType;
public Version(int build, String releaseType) {
this.build = build;
this.releaseType = releaseType;
}
public int getBuild() {
return build;
}
public String getReleaseType() {
return releaseType;
}
public void setBuild(int build) {
this.build = build;
}
public void setReleaseType(String releaseType) {
this.releaseType = releaseType;
}
}
And my root class (I called it Kernel), would love to stay with application configuration using one class
#EnableWebMvc
#Configuration
public class Kernel extends AbstractDispatcherServletInitializer implements WebMvcConfigurer {
#Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext annotationConfigWebApplicationContext = new AnnotationConfigWebApplicationContext();
annotationConfigWebApplicationContext.register(VersionController.class);
return annotationConfigWebApplicationContext;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/*" };
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}
The controller
#RestController
public class VersionController {
#RequestMapping("/version")
#ResponseBody
public Version getVersion() {
return new Version(192837, "DEV");
}
}
I am trying to go as simple as I can, I don't have any XML file in my project as I want to go fully Annotation & Java mode as long as I can.
I never really liked the XML driven concept in Spring Framework as most of time the content of these XML files looks like exposed programmer garbage that nobody but owner would understand how to setup. What is the point of exposing configuration for response serializers as deployment worker will have no clue what is that.
The error I got is:
HTTP Status 500 – Internal Server Error, No converter found for return value of type
I suspect that the Jackson is not called because Spring does not know that he is expected to use it on Version object, but I have no idea how to force Spring to do it.
My pom.xml just for sure (using Tomcat9 as web server)
<?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>pl.protean.league-craft</groupId>
<artifactId>league-craft</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warName>lc</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Kernel</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

I solved my issue thanks to this answer
https://stackoverflow.com/a/10650452/2010246
A
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
Will not work just like that even if I am overriding this method in AbstractDispatcherServletInitializer
Instead of that I had to create separate class for MVC configuration
package configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
#Configuration
public class Mvc extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
addDefaultHttpMessageConverters(converters);
}
#Bean
MappingJackson2HttpMessageConverter converter() {
return new MappingJackson2HttpMessageConverter();
}
}
Now it loads correctly and I can simply return the class like I wanted to
I guess the core problem was there were no class that is annotated as #Configuration and extends the WebMvcConfigurationSupport parent

Related

Springboot with both aspectj and Spring AOP

I am trying to get a springboot (2.6.2) project to work with both AspectJ and Spring AOP.
I have the following sample classes:
#Entity
public class Item {
#Id #Getter private String uuid = UUID.randomUUID().toString();
private String name;
#Verify.Access
public String getName() {
return name;
}
}
public #interface Verify {
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#interface Access {}
}
#Aspect
#Slf4j
public class MyAspect {
#Before("#annotation(Verify.Access)")
public void beforeAnnotation(JoinPoint joinPoint) {
log.error("BEFORE ANNOTATION");
}
}
#Aspect
#Service
public class OtherAspect {
#Autowired private MyUtility myUtility;
#Around("#annotation(SystemCall)")
public Object run(#NonNull final ProceedingJoinPoint join) throws Throwable {
return myUtility.getInfo();
}
}
#Service
#Data
public class MyUtility {
Object info;
}
My pom.xml file has the following plugins defined:
<plugin>
<groupId>com.nickwongdev</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.12.6</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<proc>none</proc>
<complianceLevel>${java.version}</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
<configuration>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
I have also defined a src/main/resources/org/aspectj/aop.xml:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<include within="mypackage..*" />
<include within="org.springframework.boot..*" />
</weaver>
<aspects>
<aspect name="mypackage.MyAspect" />
</aspects>
</aspectj>
It seems to compile okay and I see the info messages that the join points are being advised.
However, in the OtherAspect the autowired MyUtility is not getting set.
From what I could find I would expect Spring to recognize OtherAspect as a Component and Autowire in MyUtility but instead I get a NullPointerException.
Any thoughts?
Thanks!
OK, I had a little bit of time and prepared the MCVE which actually would have been your job to provide. I made the following assumptions:
You need native AspectJ, because you want to weave a target class which is not a Spring bean.
You want to use compile-time, not load-time weaaving. Therefore, you would use AspectJ Maven Plugin.
You want to use Spring dependency injection for wiring Spring beans into native AspectJ aspects, as described in the Spring manual, i.e. using an aspectOf factory method for the native aspect in Spring.
You absolutely insist on combining Lombok and native AspectJ, even though they are incompatible out of the box. I.e., you need a workaround in Maven, either binary weaving (e.g. if Lombok is only used for your non-aspect classes) or a "delombok" build step (e.g. if your aspects also use Lombok, which unfortunately they do, using the #Slf4j Lombok annotation in MyAspect.
What I changed in your setup:
I removed the dependency on Spring Data JPA to make things easier, because I was too lazy to set up a dummy in-memory database. It is not relevant for the solution here. I.e., I also commented out the #Entity and #Id annotations in class Item.
You already configured a "delombok" build step, which I wanted to stick with, because it seems to be your preference. Hence, your sample code only compiles with AspectJ Maven when using ${project.build.directory}/generated-sources/delombok as the source directory. Your idea to use a <weaveDirectory> does not work, because the aspect with the Lombok annotation does not compile that way, as it refers to the Lombok-generated static log field.
I removed the #Service annotation from the native AspectJ aspect, because that would lead to problems when wiring the application. Instead, I added a #Bean factory method to OtherAspect, so we can use #Autowired MyUtility myUtility there. In the same aspect, I also switched from #annotation(SystemCall) (due to missing code in your example) to #annotation(Verify.Access) in order to have something to test against.
I removed the superfluous aop.xml file.
I added a little Spring Boot driver application.
I switched from the no longer maintained com.nickwongdev AspectJ Maven plugin to the current dev.aspectj plugin which has more features and supports Java 17+, too.
The whole application looks like this:
<?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>org.example</groupId>
<artifactId>SO_AJ_SpringAutowireBeanNativeAspect_74661663</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<aspectj.version>1.9.9.1</aspectj.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>dev.aspectj</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.13.1</version>
<configuration>
<complianceLevel>${maven.compiler.target}</complianceLevel>
<proc>none</proc>
<showWeaveInfo>true</showWeaveInfo>
<forceAjcCompile>true</forceAjcCompile>
<sources>
<source>
<basedir>${project.build.directory}/generated-sources/delombok</basedir>
</source>
</sources>
<!--
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
-->
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
<configuration>
<addOutputDirectory>false</addOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
</project>
package org.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public #interface Verify {
#Target({ ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
#interface Access {}
}
package org.example;
import lombok.Data;
import org.springframework.stereotype.Service;
#Service
#Data
public class MyUtility {
Object info;
}
package org.example;
import lombok.Getter;
//import javax.persistence.Entity;
//import javax.persistence.Id;
import java.util.UUID;
//#Entity
public class Item {
// #Id
#Getter
private String uuid = UUID.randomUUID().toString();
private String name;
public Item(String name) {
this.name = name;
}
#Verify.Access
public String getName() {
return name;
}
}
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
#Slf4j
public class MyAspect {
#Before("#annotation(Verify.Access)")
public void beforeAnnotation(JoinPoint joinPoint) {
log.error("BEFORE ANNOTATION");
}
}
package org.example;
import lombok.NonNull;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
#Aspect
public class OtherAspect {
#Autowired
private MyUtility myUtility;
// #Around("#annotation(SystemCall)")
#Around("#annotation(Verify.Access)")
public Object run(#NonNull final ProceedingJoinPoint join) throws Throwable {
return myUtility.getInfo();
// return join.proceed();
}
}
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.Aspects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#SpringBootApplication
#Configuration
#Slf4j
public class Main {
#Bean
public OtherAspect otherAspect() {
return Aspects.aspectOf(OtherAspect.class);
}
public static void main(String[] args) {
try (ConfigurableApplicationContext appContext = SpringApplication.run(Main.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
MyUtility myUtility = appContext.getBean(MyUtility.class);
myUtility.setInfo("my info");
Item item = new Item("my name");
log.info(item.getName());
}
}
If you run the Spring Boot application, you will see the following on the console (timestamps removed):
ERROR 20680 --- [ main] org.example.MyAspect : BEFORE ANNOTATION
INFO 20680 --- [ main] org.example.Main : my info
As you can see, both aspects kick in, the first one logging an ERROR and the other one changing the return value from "my name" to "my info".
The advantage of the "delombok" variant is that within the same Maven module, you can weave aspects into the Lombok-generated source code. The disadvantage is, that in your IDE you might not be able to compile the project imported from Maven because of the very unusual custom configuration. In IntelliJ IDEA, I had to delegate the build to Maven, but still the source code editor shows squiggly lines.
As an alternative, you could create one module with Lombok compilation (no "delombok") and a second module using binary weaving in order to weave aspects into the Lombok-enhanced class files, as described here. It would all be much easier without Lombok, though. The third alternative is compilation with Lombok and native AspectJ load-time weaving configured for Spring Boot instead of compile-time or binary weaving during build time. I cannot explain and show every variant in detail here, it is a long answer already.

How to make spring batch to catch exception and continue with work without complete job?

I want to catch an exception in the item processor, do something and continue to work with the job without completing the job. And if it is possible with this to have JdbcPagingItemReader to avoid possible thread issue when reading.
Configuration:
#Configuration
#EnableJpaRepositories
#Slf4j
public class AppConfig {
private final ProcessorVerificationSkipper processorVerificationSkipper;
private final WriterVerificationSkipper writerVerificationSkipper;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final MyProcessor myProcessor;
private final MyWriter myWriter;
private final DataSource dataSource;
public AppConfig (
JobBuilderFactory jobBuilderFactory,
StepBuilderFactory stepBuilderFactory,
MyProcessor myProcessor,
MyWriter myWriter,
DataSource dataSource,
ProcessorVerificationSkipper processorVerificationSkipper,
WriterVerificationSkipper writerVerificationSkipper) {
this.processorVerificationSkipper = processorVerificationSkipper;
this.writerVerificationSkipper = writerVerificationSkipper;
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
this.myProcessor = myProcessor;
this.myWriter= myWriter;
this.dataSource = dataSource;
}
/* Without pagination
#Bean
public ItemReader<MyTable> itemReader() {
JdbcCursorItemReader contactJdbcCursorItemReader = new JdbcCursorItemReader<>();
contactJdbcCursorItemReader.setSql("SELECT * FROM MYTABLE");
contactJdbcCursorItemReader.setDataSource(dataSource);
contactJdbcCursorItemReader.setRowMapper(new BeanPropertyRowMapper<>(MyTable.class));
return contactJdbcCursorItemReader;
}*/
// with pagination
#Bean
public JdbcPagingItemReader<MyTable> itemReader() throws Exception {
return new JdbcPagingItemReaderBuilder<Object>()
.dataSource(dataSource)
.saveState(false)
.queryProvider(queryProvider())
.rowMapper(new BeanPropertyRowMapper<>(MyTable.class))
.pageSize(10)
.fetchSize(10)
.build();
}
#Bean
public PagingQueryProvider queryProvider() throws Exception {
SqlPagingQueryProviderFactoryBean provider = new SqlPagingQueryProviderFactoryBean();
provider.setDataSource(dataSource);
provider.setSelectClause("SELECT *");
provider.setFromClause("FROM MYTABLE");
provider.setSortKey("ID");
return (PagingQueryProvider)provider.getObject();
}
#Bean
TaskExecutor taskExecutorStepPush() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(2);
taskExecutor.setMaxPoolSize(20);
taskExecutor.setQueueCapacity(4);
taskExecutor.setAllowCoreThreadTimeOut(true);
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return taskExecutor;
}
#Bean
public Step step() throws Exception {
DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
attribute.setPropagationBehavior(Propagation.REQUIRED.value());
attribute.setIsolationLevel(Isolation.READ_COMMITTED.value());
// return
SimpleStepBuilder<MyTable, MyTable> builder =
(SimpleStepBuilder<MyTable, MyTable>)stepBuilderFactory.get("stepName")
.<MyTable, MyTable >chunk(10)
.reader(itemReader())
.processor(myProcessor)
.faultTolerant()
.skipLimit(Integer.parseInt(env.getProperty(CHUNK_SIZE)))
.skip(Exception.class)
.skipPolicy(processorVerificationSkipper)
.writer(myWriter)
.faultTolerant()
.skip(Exception.class)
.skipPolicy(writerVerificationSkipper)
.noRetry(Exception.class)
.noRollback(Exception.class)
.transactionAttribute(attribute);
return builder.build();
}
ProcessorVerificationSkipper.java
#Component
public class ProcessorVerificationSkipper implements SkipPolicy {
#Override
public boolean shouldSkip(Throwable throwable, int i) throws SkipLimitExceededException {
return true;
}
}
WriterVerificationSkipper.java
#Component
public class WriterVerificationSkipper implements SkipPolicy {
#Override
public boolean shouldSkip(Throwable throwable, int i) throws SkipLimitExceededException {
return true;
}
}
MyTable.java
#Getter
#Setter
#Entity(name = "MYTABLE")
public class MyTable{
#Id
#Column(name = "ID", nullable = false, precision = 0)
private Long sourceId;
#Basic
#Column(name = "A", nullable = true, length = 10)
private String a;
}
application.properties:
spring.batch.job.enabled=false
job.delay.fixed=120000
## Actuator When to show full health details.
management.endpoint.health.show-details=always
spring.main.allow-bean-definition-overriding=true
## Actuator - Endpoint IDs that should be included or '*' for all.
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=shutdown,flyway
java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
spring.datasource.jndi-name=jdbc/MyDS
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.auto-commit=false
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
MyProcessor.java:
#Slf4j
#Component
public class MyProcessor implements ItemProcessor<MyTable, MyTable> {
#Override
public Object process(MyTable myTable) {
return doSomething(myTable);
}
private Object doSomething(MyTable myTable) {
try {
myTable.setA("a");
// do something
}
catch(Exception1 e) {
myTable.setA("e1");
}
catch(Exception e) {
myTable.setA("e2");
}
return object;
}
}
MyWriter.java
#Component
public class MyWriter implements ItemWriter<MyTable> {
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public DocumentWriter(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
#Override
public void write(List<? extends MyTable> list) {
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(list.toArray());
int[] updateCounts = namedParameterJdbcTemplate.batchUpdate("UPDATE MYTABLE SET A = :a, batch);
}
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.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.myapp</groupId>
<artifactId>my-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<oracle-ojdbc8.version>12.2.0.1</oracle-ojdbc8.version>
<maven-jaxws-plugin.version>2.5</maven-jaxws-plugin.version>
<maven-jaxb2-plugin.version>2.4</maven-jaxb2-plugin.version>
<jupiter.version>5.5.0</jupiter.version>
<mockito.version>2.23.0</mockito.version>
<maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
<weblogic-wlclient.version>12.1.1</weblogic-wlclient.version>
<lombok.version>1.16.20</lombok.version>
<oracle-ojdbc.version>12.2.0.1</oracle-ojdbc.version>
<appache.http-client.version>4.5.9</appache.http-client.version>
<mockito.version>3.0.0</mockito.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<scope>provided</scope>
</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-batch</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${appache.http-client.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<profiles>
</profiles>
<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.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<classpathDependencyExcludes>
<classpathDependencyExcludes>ch.qos.logback:logback-classic</classpathDependencyExcludes>
</classpathDependencyExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<index>true</index>
<manifest>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Implementation-Version>${project.version}</Implementation-Version>
<Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
<Implementation-URL>${project.url}</Implementation-URL>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
<configuration>
<additionalProperties>
<version>${project.version}(${build.number})</version>
<Implementation-Version>${project.version}(${build.number})</Implementation-Version>
<BuildNumber>${build.number}</BuildNumber>
<BuildURL>${build.url}</BuildURL>
</additionalProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
With this when an exception occurs job finished as COMPLETED which I don't want. I want to go for all selected records to the end, no matter of exceptions, just to set the value of the property depending on the type of exception.
Is this possible?
How to configure a job?

Spring Boot #Controller not working when deploy on Tomcat standalone

I have an Spring Boot Application + ThymeLeaf, with #RestController and #Controller, everything work fine with tomcat embedded but when I deploy my app with war file to Tomcat 8.5 #Controller class not working #RestController is working fine, when I go to any page with controller use #Controller I have 404 error.
This is my 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>com.example.boot</groupId>
<artifactId>boot-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>api</artifactId>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.example.boot</groupId>
<artifactId>web</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>[5.0.2,5.1.47)</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${spring-security.version}</version>
</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>
<scope>provided</scope>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<skip>false</skip>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes>WEB-INF/lib/tomcat-*.jar</packagingExcludes>
<warName>skillinventory</warName>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/resources/</outputDirectory>
<resources>
<resource>
<directory>${project.parent.basedir}/web-si/src/main/web/dist/FrontEnd/</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This is my Spring Boot app class:
#SpringBootApplication
#EnableScheduling
#PropertySource("classpath:application.properties")
public class Application extends SpringBootServletInitializer {
#Value("${cas.service}")
private String service;
#Value("${cas.loginUrl}")
private String loginUrl;
#Value("${cas.cas30ServiceTicketValidator}")
private String cas30ServiceTicketValidator;
#Value("${cas.createAuthorityList}")
private String createAuthorityList;
#Value("${cas.key}")
private String key;
#Value("${cas.logoutFilterLink}")
private String logoutFilterLink;
#Value("${cas.setFilterProcessesUrl}")
private String setFilterProcessesUrl;
#Value("${cas.setCasServerUrlPrefix}")
private String setCasServerUrlPrefix;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(service);
serviceProperties.setSendRenew(false);
return serviceProperties;
}
#Bean
#Primary
public AuthenticationEntryPoint authenticationEntryPoint(ServiceProperties sP) {
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
entryPoint.setLoginUrl(loginUrl);
entryPoint.setServiceProperties(sP);
return entryPoint;
}
#Bean
public TicketValidator ticketValidator() {
return new Cas30ServiceTicketValidator(cas30ServiceTicketValidator);
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider provider = new CasAuthenticationProvider();
provider.setAuthenticationUserDetailsService(customUserDetailsService());
provider.setKey(key);
return provider;
}
#Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {
return token -> {
AttributePrincipal principal = token.getAssertion().getPrincipal();
String name = principal.getName();
return new User(name, "pwd", AuthorityUtils.createAuthorityList(createAuthorityList));
};
}
#Bean
public SecurityContextLogoutHandler securityContextLogoutHandler() {
return new SecurityContextLogoutHandler();
}
#Bean
public LogoutFilter logoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(logoutFilterLink, securityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl(setFilterProcessesUrl);
return logoutFilter;
}
#Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(setCasServerUrlPrefix);
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
#EventListener
public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener(HttpSessionEvent event) {
return new SingleSignOutHttpSessionListener();
}
}
My security config:
#EnableWebSecurity
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private AuthenticationProvider authenticationProvider;
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
public SpringSecurityConfig(CasAuthenticationProvider
casAuthenticationProvider,
AuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationProvider = casAuthenticationProvider;
this.authenticationEntryPoint = authenticationEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/v1/datas/**")
.permitAll()
.and()
.authorizeRequests()
.regexMatchers("/")
.authenticated()
.and()
.authorizeRequests()
.regexMatchers("/")
.permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws
Exception {
auth.authenticationProvider(authenticationProvider);
}
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Arrays.asList(authenticationProvider));
}
#Bean
public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties serviceProperties) throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(serviceProperties);
filter.setAuthenticationManager(authenticationManager());
return filter;
}
My controller with #Controller :
#Controller
public class ManagerDataController {
#Value("${theme.root}")
private String themeRoot;
#RequestMapping(value = "/hr/skilldatas", method = RequestMethod.GET)
public String goProgessData(Model model) {
model.addAttribute("themeRoot", themeRoot);
return "data-process";
}
#RequestMapping(value = "/hr/datas", method = RequestMethod.GET)
public String goDataManager(Model model) {
model.addAttribute("themeRoot", themeRoot);
return "datamanager";
}
}
I don't know why it working fine with tomcat embeded but tomcat standalone?
It turn out that because I declare thymeleaf dependency scope is provided, it not Spring false, after I change scope to compile it working now.

Spring 5 MVC - InternalResourceViewResolver and Spring Security

I'm learning Spring, and I've got stuck on some issues i can't resolve. I run it on a GlassFish Server.
I'm implementing a simple WebMvcConfigurer which has an InternalResourceViewResolver, it looks like this:
#Configuration
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
return source;
}
#Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
}
and my Controller:
#WebServlet(value = "/")
#Controller
public class HomeController extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("index.jsp").forward(request,response);
}
}
I would assume that when I run the app, it would open the index.jsp file, but it doesn't, instead I get a 404. When I change it to
request.getRequestDispatcher("/WEB-INF/views/index.jsp").forward(request,response);
it opens it.
Also, I've followed the documentation on Spring Security and implemented simple security. From my understanding, every request should be authenticated and it should redirect the user to a login page, but it doesn't.
Here is the code:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("user").roles("USER").build());
manager.createUser(User.withUsername("admin").password("admin").roles("USER", "ADMIN").build());
return manager;
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
}
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{ApplicationConfig.class, WebSecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebMvcConfig.class };
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
// you might want to add stuff to enable spring security
return new Filter[]{characterEncodingFilter};
}
}
#Configuration
public class ApplicationConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
I'm suspecting that the issues are related, but can't see what I'm missing here. When i change the path in the Controller as mentioned above, I do not get redirected to the login page.
Here is the 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>
<groupId>org.vives</groupId>
<artifactId>spring-mvc-quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring-mvc-quickstart</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java-version>1.8</java-version>
<!-- Override Spring version -->
<spring.version>5.0.0.RELEASE</spring.version>
<jackson.version>2.9.1</jackson.version>
<thymeleaf-extras-java8time-version>3.0.1.RELEASE</thymeleaf-extras-java8time-version>
<!-- AssertJ is not a part of Spring IO platform, so the version must be provided explicitly -->
<assertj-core-version>3.8.0</assertj-core-version>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<!-- Avoid issue #72 Could not initialize class org.thymeleaf.templateresolver.ServletContextTemplateResolver due to 'validation is not supported' -->
<exclusions>
<exclusion>
<artifactId>pull-parser</artifactId>
<groupId>pull-parser</groupId>
</exclusion>
</exclusions>
<version>5.2.9.Final</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-release</id>
<name>Spring Release Repository</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<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>
Can someone explain to me what is happening or what I'm doing wrong?
I've finally resolved the issues I had.
As for security, i forgot to add SecurityWebApplicationInitializer and as for navigation, this link helped me.

spring framework 3.2.9 annotations

i try to use spring framework 3.2.9
that's my 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>com.mkyong.common</groupId>
<artifactId>3_2_9</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>3_2_9</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.9.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>3_2_9</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>WebContent\WEB-INF\web.xml</webXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
and i have 3 classes
*hello/MessageService.java:
package hello;
public interface MessageService {
String getMessage();
}
*hello/MessagePrinter.java
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class MessagePrinter {
final private MessageService service;
#Autowired
public MessagePrinter(MessageService service) {
this.service = service;
}
public void printMessage() {
System.out.println(this.service.getMessage());
}
}
*hello/Application.java
package hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
#Configuration
#ComponentScan
public class Application {
#Bean
MessageService mockMessageService() {
return new MessageService() {
public String getMessage() {
return "Hello World!";
}
};
}
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(Application.class);
MessagePrinter printer = context.getBean(MessagePrinter.class);
printer.printMessage();
}
}
but the import cannot be resolved and the annotations that i have used are no known.any one can help me..
The #Autowired annotation resides in the spring-beans project, try adding the following dependency to your pom:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.9.RELEASE</version>
</dependency>

Resources