Problems setting up Spring form validation - spring

I have some problems setting up the validation in Spring MVC (4.3.9) application.
Basically, there is a simple application, with the issue isolated to one "contact" form.
Here is part of the code of the bean underlying the form:
#Component
#Scope("request")
public class SendMail {
#Min(20)
private String userName;
#Size(min=10, max=11)
private String message;
private String userEmail;
public static class CustomValidator implements Validator {
#Override
public boolean supports(Class clazz) {
return SendMail.class.equals(clazz);
}
#Override
public void validate(Object targets, Errors errors) {
SendMail o = (SendMail) targets;
if (o.getUserName() == null || o.getUserName().length() < 1) {
errors.rejectValue("userName", "Empty.userName");
}
}
}
....
}
and here is the part of the relevant controller:
#RequestMapping(value = {"/contact"}, method = RequestMethod.POST)
public ModelAndView sendEmail(#Valid SendMail sendmail, BindingResult result) {
System.out.println("Result1: " + result.hasErrors());
DataBinder binder = new DataBinder(sendmail);
binder.setValidator(new SendMail.CustomValidator());
binder.validate();
result = binder.getBindingResult();
System.out.println("Result2: " + result.hasErrors());
I get the following result:
Result1: false
Result2: true
So, the 'general' (denoted by the #Valid annotation) validation doesnt seem to work, but a manually-invoked validation does.
I googled for some time and have come across suggestions that a validation bean needs to be defined in the spring config. Unfortunately, when I add the following to my Config.java:
....
#Bean(name = "validator")
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
return validator;
}
The application crashes with the following exception:
....
root cause
java.lang.ClassNotFoundException: javax.el.ExpressionFactory
java.net.URLClassLoader.findClass(URLClassLoader.java:381)
java.lang.ClassLoader.loadClass(ClassLoader.java:424)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
java.lang.ClassLoader.loadClass(ClassLoader.java:357)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:763)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
java.net.URLClassLoader.access$100(URLClassLoader.java:73)
java.net.URLClassLoader$1.run(URLClassLoader.java:368)
java.net.URLClassLoader$1.run(URLClassLoader.java:362)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:361)
java.lang.ClassLoader.loadClass(ClassLoader.java:424)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
java.lang.ClassLoader.loadClass(ClassLoader.java:411)
java.lang.ClassLoader.loadClass(ClassLoader.java:357)
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:348)
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(Unknown Source)
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(Unknown Source)
javax.el.ExpressionFactory.newInstance(Unknown Source)
javax.el.ExpressionFactory.newInstance(Unknown Source)
....
This supposedly indicates, there is no lib with EL implementation. And here is where I'm stuck. I have tried a number of dependency (using maven) with no avail. Currently the relevant part of my pom looks like this:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>5.4.1.Final</version>
</dependency>
I have tried various set-ups, with el-impl 2.2, etc. addin el.jar to Tomcat clasppath. But no luck at all =(
What is even more starange, if you look at the exception above, the call actually goes through "javax.el.ExpressionFactory.newInstance(Unknown Source)" before resulting in "java.lang.ClassNotFoundException: javax.el.ExpressionFactory".
I'd be grateful for any hints on how to fix/debug the issue...

Add this dependency .
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>
Follow solution here .

I have found the solution to my issue. Strange as it seems, when I added el.jar supplied with Tomcat to the classpath in catalina.sh, the validation works. It might be a distro-related issue (i'm running it on Gentoo).

Related

Method Annotated with #EventHandler is not getting triggered in Axon Based Spring Boot Microservice

The event is getting stored in the event store but not getting persisted in the Entity table.
My Controller method
#PostMapping("/saveProduct")
public ResponseEntity<Void> productCreator(#RequestBody CreateProductModel createProductModel){
CreateProductCommand createProductCommand = CreateProductCommand.builder().
productId(UUID.randomUUID().toString()).
title(createProductModel.getTitle()).
description(createProductModel.getDescription()).
price(createProductModel.getPrice()).
discountPercentage(createProductModel.getDiscountPercentage()).
available(createProductModel.isAvailable()).build();
try {
commandGateway.sendAndWait(createProductCommand);
}catch(Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
Aggregate Class
#Aggregate
public class ProductAggregate {
#AggregateIdentifier
private String productId;
private String title;
private String description;
private int price;
private short discountPercentage;
private boolean available;
public ProductAggregate() {
//leave it blank always
}
#CommandHandler
public ProductAggregate(CreateProductCommand createProductCommand) {
ProductCreatedEvent productCreatedEvent = new ProductCreatedEvent();
BeanUtils.copyProperties(createProductCommand, productCreatedEvent);
AggregateLifecycle.apply(productCreatedEvent);
}
#EventSourcingHandler
public void on(ProductCreatedEvent productCreatedEvent) {
this.productId = productCreatedEvent.getProductId();
this.title = productCreatedEvent.getTitle();
this.description = productCreatedEvent.getDescription();
this.price = productCreatedEvent.getPrice();
this.discountPercentage = productCreatedEvent.getDiscountPercentage();
this.available = productCreatedEvent.isAvailable();
}
}
But this below class's method public void on(ProductCreatedEvent productCreatedEvent) is not getting called because of which the events are getting stored in event store but not getting persisted. Can someone help why this is happening?
#Service
public class ProductEventsHandler {
private final ProductRepo productRepo;
public ProductEventsHandler(ProductRepo productRepo) {
this.productRepo = productRepo;
}
#EventHandler
public void on(ProductCreatedEvent productCreatedEvent) {
//1. Create object of entity
Product product = new Product();
//2. Copy from productCreatedEvent(event) to entity
BeanUtils.copyProperties(productCreatedEvent, product);
//3. repository.save(entity);
productRepo.save(product);
}
}
Also, I am getting an exception while running the application as below :
2021-11-07 00:19:20.677 INFO 6668 --- [ main] com.netflix.discovery.DiscoveryClient : Initializing Eureka in region us-east-1
2021-11-07 00:19:20.719 INFO 6668 --- [ main] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
2021-11-07 00:19:20.782 WARN 6668 --- [s.CQRS.query]-0] o.a.e.TrackingEventProcessor : Error occurred. Starting retry mode.
com.thoughtworks.xstream.security.ForbiddenClassException: com.solinvictus.Products.CQRS.events.ProductCreatedEvent
at com.thoughtworks.xstream.security.NoTypePermission.allows(NoTypePermission.java:26) ~[xstream-1.4.18.jar:1.4.18]
at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:74) ~[xstream-1.4.18.jar:1.4.18]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.18.jar:1.4.18]
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47) ~[xstream-1.4.18.jar:1.4.18]
at org.axonframework.serialization.AbstractXStreamSerializer.classForType(AbstractXStreamSerializer.java:159) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.serialization.LazyDeserializingObject.<init>(LazyDeserializingObject.java:83) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.EventUtils.lambda$upcastAndDeserializeTrackedEvents$1(EventUtils.java:99) ~[axon-messaging-4.2.jar:4.2]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_202]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_202]
at org.axonframework.eventsourcing.eventstore.BatchingEventStorageEngine$EventStreamSpliterator.tryAdvance(BatchingEventStorageEngine.java:242) ~[axon-eventsourcing-4.2.jar:4.2]
at java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:294) ~[na:1.8.0_202]
at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206) ~[na:1.8.0_202]
at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161) ~[na:1.8.0_202]
at java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:300) ~[na:1.8.0_202]
at java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681) ~[na:1.8.0_202]
at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peekPrivateStream(EmbeddedEventStore.java:397) ~[axon-eventsourcing-4.2.jar:4.2]
at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peek(EmbeddedEventStore.java:356) ~[axon-eventsourcing-4.2.jar:4.2]
at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.hasNextAvailable(EmbeddedEventStore.java:333) ~[axon-eventsourcing-4.2.jar:4.2]
at org.axonframework.common.stream.BlockingStream.hasNextAvailable(BlockingStream.java:40) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.TrackingEventProcessor.checkSegmentCaughtUp(TrackingEventProcessor.java:464) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.TrackingEventProcessor.processBatch(TrackingEventProcessor.java:351) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.TrackingEventProcessor.processingLoop(TrackingEventProcessor.java:275) ~[axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.TrackingEventProcessor$TrackingSegmentWorker.run(TrackingEventProcessor.java:1071) [axon-messaging-4.2.jar:4.2]
at org.axonframework.eventhandling.TrackingEventProcessor$WorkerLauncher.run(TrackingEventProcessor.java:1183) [axon-messaging-4.2.jar:4.2]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_202]
You've encountered a failure in Axon's upcaster because of a ForbiddenClassException thrown by XStream.
2021-11-07 00:19:20.782 WARN 6668 --- [s.CQRS.query]-0] o.a.e.TrackingEventProcessor : Error occurred. Starting retry mode.
com.thoughtworks.xstream.security.ForbiddenClassException: com.solinvictus.Products.CQRS.events.ProductCreatedEvent
To solve this you should allow XStream for your event classes to be serialized as stated in this answer
There were two issues that I found in my code :
The issue was with XStream so I excluded the Xstream dependency from the axon framework and added the XStream dependency myself ().
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-spring-boot-starter</artifactId>
<version>4.2</version>
<exclusions>
<exclusion>
<groupId>org.axonframework</groupId>
<artifactId>axon-server-connector</artifactId>
</exclusion>
<exclusion>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.17</version>
</dependency>
The silly one:
I had annotated the "id" field of the entity class with #GeneratedValue and since I was populating the value using UUID that was causing the error. It was causing the error. I didn't notice this issue until I did the 1st fix(mentioned above)

Use ElasticSearch client in non web application with Spring

I'm creating a non web application with Spring that will read data from Kafka and write it in ElasticSearch, i included the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
And the following configuration class:
#Configuration
public class ElasticSearchConfig extends AbstractElasticsearchConfiguration{
#Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
When i execute the following code:
#Override
public void run(String... args) throws Exception {
IndexRequest request = new IndexRequest("test-transactions");
request.id("2");
request.source("{\"name\":\"Sammie\"," + "\"lastname\":\"Goldner\"," + "\"username\":\"hugh.vonrueden\","
+ "\"amount\":9622235.2009}", XContentType.JSON);
client.index(request, RequestOptions.DEFAULT);
}
I get the following exception:
Caused by: java.lang.ClassNotFoundException: org.springframework.http.HttpHeaders
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_251]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_251]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355) ~[na:1.8.0_251]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_251]
... 46 common frames omitted
If i include the following dependency the code works fine:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
But it brings a lot of other functionalities that i don't want in my code, is there any other way to configure spring-boot-starter-data-elasticsearch in a non web application?
Thanks.

Spring Boot test tries to initialize cache2k for the 2nd time and fails

After adding cache2k to my project some #SpringBootTest's stopped working with an error:
java.lang.IllegalStateException: Cache already created: 'cache'
Below I provide the minimal example to reproduce:
Go to start.spring.io and create a simplest Maven project with Cache starter, then add cache2k dependencies:
<properties>
<java.version>1.8</java.version>
<cache2k-version>1.2.2.Final</cache2k-version>
</properties>
<dependencies>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>${cache2k-version}</version>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>${cache2k-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-spring</artifactId>
<version>${cache2k-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Now configure the simplest cache:
#SpringBootApplication
#EnableCaching
public class CachingDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CachingDemoApplication.class, args);
}
#Bean
public CacheManager springCacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
cacheManager.addCaches(b -> b.name("cache"));
return cacheManager;
}
}
And add any service (which we will #MockBean in one of our tests:
#Service
public class SomeService {
public String getString() {
System.out.println("Executing service method");
return "foo";
}
}
Now two #SpringBootTest tests are required to reproduce the issue:
#SpringBootTest
#RunWith(SpringRunner.class)
public class SpringBootAppTest {
#Test
public void getString() {
System.out.println("Empty test");
}
}
#RunWith(SpringRunner.class)
#SpringBootTest
public class WithMockedBeanTest {
#MockBean
SomeService service;
#Test
public void contextLoads() {
}
}
Notice that the 2nd test has mocked #MockBean. This causes an error (stacktrace below).
Caused by: java.lang.IllegalStateException: Cache already created: 'cache'
at org.cache2k.core.CacheManagerImpl.newCache(CacheManagerImpl.java:174)
at org.cache2k.core.InternalCache2kBuilder.buildAsIs(InternalCache2kBuilder.java:239)
at org.cache2k.core.InternalCache2kBuilder.build(InternalCache2kBuilder.java:182)
at org.cache2k.core.Cache2kCoreProviderImpl.createCache(Cache2kCoreProviderImpl.java:215)
at org.cache2k.Cache2kBuilder.build(Cache2kBuilder.java:837)
at org.cache2k.extra.spring.SpringCache2kCacheManager.buildAndWrap(SpringCache2kCacheManager.java:205)
at org.cache2k.extra.spring.SpringCache2kCacheManager.lambda$addCache$2(SpringCache2kCacheManager.java:143)
at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1853)
at org.cache2k.extra.spring.SpringCache2kCacheManager.addCache(SpringCache2kCacheManager.java:141)
at org.cache2k.extra.spring.SpringCache2kCacheManager.addCaches(SpringCache2kCacheManager.java:132)
at com.example.cachingdemo.CachingDemoApplication.springCacheManager(CachingDemoApplication.java:23)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca.CGLIB$springCacheManager$0(<generated>)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca$$FastClassBySpringCGLIB$$bbd240c0.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at com.example.cachingdemo.CachingDemoApplication$$EnhancerBySpringCGLIB$$2dce99ca.springCacheManager(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 52 more
If you remove #MockBean, both tests will pass.
How can I avoid this error in my test suite?
Your second test represents a different ApplicationContext altogether so the test framework will initiate a dedicated one for it. If cache2k is stateful (for instance sharing the CacheManager for a given classloader if it already exists), the second context will attempt to create a new CacheManager while the first one is still active.
You either need to flag one of the test as dirty (see #DirtiesContext) which will close the context and shut down the CacheManager, or you can replace the cache infrastructure by an option that does not require all that, see #AutoConfigureCache.
If cache2k works in such a way that it requires you to dirty the context, I'd highly recommend to swap it using the later options.
Since I do not want any custom behavior in test, but just want to get rid of this error, the solution is to create CacheManager using unique name like this:
#Bean
public CacheManager springCacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager("spring-" + hashCode());
cacheManager.addCaches(b -> b.name("cache"));
return cacheManager;
}
I encountered the same error when using cache2k with Spring Dev Tools, and ended up with the following code as the solution:
#Bean
public CacheManager cacheManager() {
SpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();
// To avoid the "Caused by: java.lang.IllegalStateException: Cache already created:"
// error when Spring DevTools is enabled and code reloaded
if (cacheManager.getCacheNames().stream()
.filter(name -> name.equals("cache"))
.count() == 0) {
cacheManager.addCaches(
b -> b.name("cache")
);
}
return cacheManager;
}

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test.spring_session' doesn't exist - Spring Boot

I am developing springboot-springsession-jdbc-demo. When I simply run the code I get the following error. It looks to me some property must need to set in application.properties in order create the schema/tables before hand. Required configuration is already in placed and still it gives error. The code is present in https://github.com/sivaprasadreddy/spring-session-samples
The error for reference:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [DELETE FROM SPRING_SESSION WHERE LAST_ACCESS_TIME < ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test.spring_session' doesn't exist
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:870) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:931) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:941) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.session.jdbc.JdbcOperationsSessionRepository$6.doInTransaction(JdbcOperationsSessionRepository.java:481) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.jdbc.JdbcOperationsSessionRepository$6.doInTransaction(JdbcOperationsSessionRepository.java:478) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.session.jdbc.JdbcOperationsSessionRepository.cleanUpExpiredSessions(JdbcOperationsSessionRepository.java:478) ~[spring-session-1.2.1.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_45]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_45]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test.spring_session' doesn't exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_45]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_45]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_45]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_45]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.Util.getInstance(Util.java:387) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:942) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2673) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5098) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994) ~[mysql-connector-java-5.1.39.jar:5.1.39]
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:877) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:870) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) ~[spring-jdbc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 21 common frames omitted
pom.xml
<!-- Parent pom providing dependency and plugin management for applications
built with Maven -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Starter JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<!-- Spring Boot devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- H2 DB -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
</project>
Application.java
#SpringBootApplication
#EnableJdbcHttpSession
#EnableAutoConfiguration
public class Application{
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
HomeController.java
#Controller
public class HomeController {
private static final AtomicInteger UserId = new AtomicInteger(0);
#RequestMapping("/")
public String home(Model model){
return "index";
}
#RequestMapping("/add-simple-attrs")
public String handleSimpleSessionAttributes(HttpServletRequest req, HttpServletResponse resp){
String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue);
User user = new User();
user.setName(attributeValue);
req.getSession().setAttribute(attributeName, user);
return "redirect:/";
}
#RequestMapping("/add-object-attrs")
public String handleObjectSessionAttributes(HttpServletRequest req, HttpServletResponse resp){
String name = req.getParameter("name");
User user = new User();
user.setId(UserId.incrementAndGet());
user.setName(name);
req.getSession().setAttribute("USER_ID_"+user.getId(), user);
return "redirect:/";
}
}
User.java
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public User(){
}
public User(Integer id, String name){
this.id = id;
this.name = name;
}
#Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
public Integer getId(){
return id;
}
public void setId(Integer id){
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
application.properties
logging.level.org.springframework=INFO
################### DataSource Configuration ##########################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.initialize=true
#spring.datasource.data=classpath:org/springframework/session/jdbc/schema-h2.sql
spring.datasource.data=classpath:org/springframework/session/jdbc/schema-mysql.sql
spring.datasource.continue-on-error=true
spring.jpa.hibernate.ddl-auto=create
#spring.jpa.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>Home</title>
</head>
<body>
<h2 th:text="#{app.title}">App Title</h2>
<h4>Add Simple Attributes To Session</h4>
<form class="form-inline" role="form" action="add-simple-attrs" method="post">
<label for="attributeName">Attribute Name</label>
<input id="attributeName" type="text" name="attributeName"/>
<label for="attributeValue">Attribute Value</label>
<input id="attributeValue" type="text" name="attributeValue"/>
<input type="submit" value="Set Attribute"/>
</form>
<h4>Add Object Attributes To Session</h4>
<form class="form-inline" role="form" action="add-object-attrs" method="post">
<label for="name">User Name</label>
<input id="name" type="text" name="name"/>
<input type="submit" value="Save"/>
</form>
<h3>Session Attributes</h3>
<table>
<thead>
<tr>
<th>Attribute Name</th>
<th>Attribute Value</th>
</tr>
</thead>
<tbody>
<tr th:each="attr : ${session}">
<td th:text="${attr.key}">Name</td>
<td th:text="${attr.value}">Value</td>
</tr>
</tbody>
</table>
</body>
</html>
I've just had a quite similar error while using spring-boot 2.0.5 (as opposed to 1.4.0 used by OP) with Postgres driver:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [DELETE FROM spring_sessions WHERE EXPIRY_TIME < ?]; nested exception is org.postgresql.u
til.PSQLException: ERROR: relation "spring_sessions" does not exist
Position: 13
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:234) ~[spring-jdbc-5.0.8.RELEASE.jar!/:5.0.8.RELEA
SE]
// redacted...
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
Caused by: org.postgresql.util.PSQLException: ERROR: relation "spring_sessions" does not exist
Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) ~[postgresql-42.2.2.jar!/:42.2.2]
// redacted...
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605) ~[spring-jdbc-5.0.8.RELEASE.jar!/:5.0.8.RELEASE]
... 16 common frames omitted
According to documentation, setting up Spring Session backed by a relational database is as simple as adding a single configuration property to your application.properties:
spring.session.store-type=jdbc
Note that in order to get the session tables auto-created, I had to also specify:
spring.session.jdbc.initialize-schema=always
Once this setting specified, Spring used the correct SQL initialization script from spring-session-jdbc jar. My mistake was not specifying that option - in which case embedded was being used as default value.
I'm not sure this is the best solution (or even the solution as i'm new to spring and am not aware of the repercussions of doing this) but I was having the same issue, managed to solve it by deleting the annotation #EnableJdbcHttpSession
According to Vedran Pavic:
The reason spring.session.* do not work for you is because your are
using #EnableJdbcHttpSession. That means that you are configuring
Spring Session explicitly, so Spring Boot backs off with its
auto-configuration.
You should remove #EnableJdbcHttpSession and ensure Spring Boot is
auto-configuring Spring Session. Additionally, you could also leave
spring.session.store-type out, since Spring Boot should be able to
deduce which session repository implementation are you using as long
as you have only only SessionRepository implementation on the
classpath (i.e. you depend only on spring-session-jdbc and no other
Spring Session modules).
Original Post
This will solve your immediate problem, but i'm unsure if it will break something else...
I think you have multiple issues By default jdbc has H2 database. It is automatically created by spring.
Check if it is there. So first run it on H2. Then copy the same database and table to MySQL. create same schema and table to MySQL then change connection to MySQL.
Spring Boot automatically creates a DataSource that connects Spring Session to an embedded instance of H2 database
src/main/resources/application.properties
spring.datasource.url= # JDBC URL of the database.
spring.datasource.username= # Login username of the database.
spring.datasource.password= # Login password of the database.
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root

Facebook instance not getting created in Spring Social

I am trying to run a simple Spring Social application to login to Facebook account. But, Facebook instance is not created and it is showing nullpointerexception.
#Controller
#RequestMapping("/fb")
public class HelloFBController {
#Autowired
private Facebook facebook;
#RequestMapping(method = RequestMethod.GET)
public String helloFacebook(Model model) {
if (!facebook.isAuthorized()) {
return "redirect:/connect/facebook";
}
model.addAttribute("feed", facebook.feedOperations().getFeed());
return "hellofb";
}
}
Then
#Configuration
public class SocialConfig {
#Bean
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(new FacebookConnectionFactory(
environment.getProperty("facebook.appId"),
environment.getProperty("facebook.appSecret")));
return registry;
}
#Inject
private Environment environment;
}
Then application.properties file
spring.social.facebook.appId=XXXXXXXXXXXX
spring.social.facebook.appSecret=XXXXXXXXXXXXXXXXXXX
Then pom.xml is
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-social-facebook</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
Whether I am missing something. When I run this application using Spring Boot, I am getting the exception in Controller as bellow. I am trying to access the application at localhost:8080/fb
java.lang.NullPointerException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at $Proxy42.isAuthorized(Unknown Source)
at net.javabeat.spring.social.web.HelloFBController.helloFacebook(HelloFBController.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvok
You are missing the facebook dependency, see below:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-facebook</artifactId>
</dependency>
Follow link below for more information:
Accessing Facebook Data
Do you have this project in a Git repository somewhere that I could try without having to recreate the example from the blog entry you pulled it from?
I also notice that your Maven dependencies are reference Spring Boot starters for Spring Social Facebook, but that you are explicitly configuring the connection factory locator (and nothing else). Consequently, if you are using Spring Boot, then your explicit configuration is probably disabled auto-configuration provided by Spring Boot. Delete SocialConfig and see what happens.
You can change the code for a workaround to make it working. At this time facebook is not connnected or injected so it is getting NPE:
try {
if (!facebook.isAuthorized()) {
return "redirect:/connect/facebook";
}
} catch (Exception e) {
return "redirect:/connect/facebook";
}
Also, you may have to add spring.social.auto_connection_views=true if you are not using custom view.

Resources