Spring Data Rest and Hateoas - spring

I was following a simple tutorial to test the behavior of spring data rest, with annotating a repository with #RestResource annotation.
I have very simple scenario:
Jpa User Entity and UserRepository annotated with #RestResource
#RestResource(path="users", rel="users")
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
List<User> findUserByUserName(#Param("userName")String userName);
}
I use annotation config initialization and I try to register RepositoryRestMvcConfiguration, so the UserRepository can be registered.
But my application is not starting and I have the following exception
INFO Registering annotated classes: [class org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration,class com.ncau.WebMvcConfiguration]
ERROR Context initialization failed
java.lang.ClassCastException: [Lorg.springframework.hateoas.config.EnableHypermediaSupport$HypermediaType; cannot be cast to org.springframework.hateoas.config.EnableHypermediaSupport$HypermediaType
at org.springframework.hateoas.config.HypermediaSupportBeanDefinitionRegistrar.registerBeanDefinitions(HypermediaSupportBeanDefinitionRegistrar.java:90) ~[spring-hateoas-0.8.0.RELEASE.jar:na]
I use
spring-hateoas: 0.8.0.RELEASE
spring-data-rest-webmv: 2.0.0.RC1
spring-framework: 4.0.0.RELEASE
spring-data-jpa:1.4.3

For SDR 2.0.0.RC1, use
spring-hateoas 0.9.0.RELEASE
spring-data-jpa 1.5.0.RC1
SDR will export all repositories by default, you don't need to annotate them.

Related

DI in tests without using spring boot (#SpringBootTest)

Switching from spring boot back to "normal" spring because the app only uses some jdbc code to "upsert" into a postgresql database.
1)
tried annotating the test class with:
#RunWith(SpringJUnit4ClassRunner.class)
public class DBIntegration {
results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
2)
tried annotating the class with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
public class DBIntegration {
[main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [de.mydomain.myproject.DBIntegration]: no resource found for suffixes {-context.xml}.
No exceptions, but java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=insertDataFrom_sometest],
3) tried annotating the class with:
#Component
public class DBIntegration {
dependency injection does not work in this case, the expected service
(to be injected) throws a nullpointerexception

Spring-boot repository not being registered as a valid bean

Spring-boot does not seem to want to register my repository as a valid bean :( Here is the error I am seeing:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.frustrated.stats.MyRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
The underlying cause seems to be:
o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not a concrete top-level class: file [/Users/me/Code/my_app/my_service/build/classes/java/main/com/frustrated/stats/MyRepository.class]
Have I configured my application improperly somewhere?
Here are my files:
MyRepository.java:
package com.frustrated.stats;
#Repository
public interface MyRepository extends JpaRepository<StatsEvent, Long> {}
StatsEvent.java:
package com.frustrated.stats;
#Entity
public class StatsEvent { ... }
Application.java:
#SpringBootApplication
#ComponentScan(basePackages = { "com.frustrated" })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer {
Here is my package structure:
com:
frustrated:
- Application.java
stats:
- MyRepository.java
- StatsEvent.java
Attempts to Debug
After trying a lot of different annotations, I thought it may be more productive to simply step through the registration process. I have traced the code, and it seems to be failing here:
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
It is the metadata.hasAnnotatedMethods(Lookup.class.getName()) that is false and causing my repository to not be instantiated as such.
It may also be of note that my StatsEvent is also ignored because:
o.s.c.a.ClassPathBeanDefinitionScanner : Ignored because not matching any filter: file [/Users/me/Code/my_app/my_service/build/classes/java/main/com/frustrated/stats/StatsEvent.class]
Any help would be greatly appreciated!
Judging by MyRepository extending JpaRepository, you are trying to use Spring Data JPA but your have excluded the auto-configuration for Hibernate and a DataSource. Unless you have some manual configuration for Hibernate or another JPA provider that you haven't shown, the support for JpaRepository will be disabled as it requires a JPA provider and a data source.
Try to add this on top of your Application.class
#EnableJpaRepositories(basePackages = "com.frustrated.stats.MyRepository")
#ComponentScan("com.frustrated.stats.service") // if you have it
#EntityScan("com.frustrated.stats.entity") // of your entities

Spring Boot: How to make single externalize JDBC datasource configuration work in differnt DAOImpl classes

I have a requirement to fetch DB username and password from Vault. So I have removed the default implementation (spring.datasource.url,spring.datasource.username,spring.datasource.password)
and added the following code in DAOImpl class.
Code
#Autowired
private JdbcTemplate jdbcTemplate;
#Bean
#Primary
public DataSource dataSource()
{
return DataSourceBuilder.create().username("someusername").password("somepassword")
.url("someurl")
.driverClassName("oracle.jdbc.driver.OracleDriver").build();
}
It was working perfectly. But when I added a new DAOImpl class I got the following Exception. Is it necessay to add the above code snippet in all the DAOImpl
classes. Is there a way to configure dataSource in single class and use it in all the DAOImpl classes
Exception
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?

Spring Data: Can't Autowire #Repository JpaRepository Interface: "expected at least 1 bean which qualifies as autowire candidate"

My question is almost identical to this one but not the same, because I'm NOT using Spring Boot.
Can't Autowire #Repository annotated interface in Spring Boot
So I can't do #EnableJpaRepositories there's no Spring Boot Runner in my case. I have SpringMVC Controllers inside a Web app.
I'm using Spring Data independently, in a regular old-school SpringMVC application.
I'm getting the error
Caused by: No qualifying bean of type 'com.myapp.dao.QuestionsDAO' available:
expected at least 1 bean which qualifies as autowire candidate.
DAO Interface for Spring Data, note #Repository:
#Repository
public interface QuestionsDAO extends JpaRepository<Question, Long> {
public String findById(Long id);
}
A Service should then use this DAO, autowired:
Component
public class SchedulingService {
#Autowired
QuestionsDAO questionsDAO;
public String findLabelById(Long id) {
return questionsDAO.findById(id);
}
}
Component Scan is enabled, works for everything else.
<context:component-scan base-package="com.myapp" />
Is Spring Data only allowed with Spring Boot?
The annotation #EnableJpaRepositories comes from Spring Data, it has nothing to do with Spring Boot. So it would be enough, to have one class annotated with #Configuration and #EnableJpaRepositories.
If you want to do it in XML, you have to add
<jpa:repositories base-package="com.acme.repositories" />
You also don't need the #Repository annotation on your interfaces, that annotation has another purpose.

Play Framework with Spring, #Transactional not working

I'm using Play Framework (2.2.2) in combination with Spring (using this template: https://github.com/jamesward/play-java-spring).
If I annotate the Application Controller with #Transactional it's working fine:
#org.springframework.stereotype.Controller
#Transactional
public class Application {
// ...
}
However, if I also extend from Play's Base Controller I get the following error:
[NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined]
Code:
#org.springframework.stereotype.Controller
#Transactional
public class Application extends play.mvc.Controller{
// ...
}
So for some reason the #TransactionalAnnotation combined with extends play.mvc.Controller leads to a NoSuchBeanDefinitionException.
Using either #Transactional OR extends play.mvc.Controller (not both combined) and Spring can instantiate the controller bean just fine.
How can I make them both work together?
This is the full stackstrace:
play.api.Application$$anon$1: Execution exception[[NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined]]
at play.api.Application$class.handleError(Application.scala:293) ~[play_2.10.jar:2.2.2]
at play.api.DefaultApplication.handleError(Application.scala:399) [play_2.10.jar:2.2.2]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2$$anonfun$applyOrElse$3.apply(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
at scala.Option.map(Option.scala:145) [scala-library.jar:na]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$2.applyOrElse(PlayDefaultUpstreamHandler.scala:261) [play_2.10.jar:2.2.2]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [controllers.Application] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:296) ~[spring-beans.jar:3.2.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1125) ~[spring-context.jar:3.2.3.RELEASE]
at Global.getControllerInstance(Global.java:21) ~[na:na]
at play.core.j.JavaGlobalSettingsAdapter.getControllerInstance(JavaGlobalSettingsAdapter.scala:46) ~[play_2.10.jar:2.2.2]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:57) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:57) ~[na:na]
Actually the controller itself should not be transactional, as transactionality is a concern of the service layer and not the presentation/web layer or the repository layer.
There are several reasons for this, for example the controller layer might trigger several business transactions. It's possible to make a controller transactional but it's not recommended practice, if you move the #Transactional annotation from the controller to the #Service layer, it will surely work.

Resources