I am trying to write a simple Spring Data JPA app for Spring Boot in Groovy. I followed the getting started guide and did some basic transformation to make it work with Groovy and the Spring Boot CLI.
I am running the code with the Spring Boot CLI (v1.1.8):
spring run app.groovy
This results in the error:
NoSuchBeanDefinitionException: No qualifying bean of type [hello.CustomerRepository] is defined
Does anyone have an idea why the Repository is not getting created automatically? I feel like I must be missing something simple. Here is the app.groovy file containing all of the code:
package hello
#Grab("spring-boot-starter-data-jpa")
#Grab("h2")
import java.util.List
import javax.persistence.*
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.Configuration
import org.springframework.data.repository.CrudRepository
#Entity
class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
long id
String name
Customer() {}
Customer(String name) {
this.name = name
}
}
interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByName(String name)
}
#Configuration
#EnableAutoConfiguration
class Application implements CommandLineRunner {
#Autowired
ConfigurableApplicationContext context
void run(String[] args) {
CustomerRepository repository = context.getBean(CustomerRepository.class)
repository.save(new Customer("Jack", "Bauer"))
}
}
A Groovy CLI app can only scan for JPA repositories if you give it actual classes (i.e. not the .groovy scripts). You can build a jar file and run that, and it should work:
$ spring jar app.jar app.groovy
$ java -jar app.jar
Related
I am experimenting with spring boot multi module projects for my understanding.
My Over All Goal is :
1.Build Spring boot project as independent jar and utilise it on another project.
2.Autowire Bean properties inside jar as per new project. Make it independent.
Things I have done so far.
Project providerModule1
Declare a Service(MyService).
#Component
public class MyService {
#Autowired
ServiceProperties serviceProperties;
public String getInfoFromProperties() {
return serviceProperties.toString();
}
}
Create a bean called ServiceProperties that will be used in to MyService.
package com.demo.multimodule.providerModule1.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import lombok.Data;
#Component
#Data
public class ServiceProperties {
#Value("${default.userName}")
private String name;
#Value("${default.email}")
private String email;
#Value("${default.age}")
private String age;
}
Load the bean ServiceProperties by reading propeties from yml file.
default:
userName: userName1
email: default#email.com
age: 18
Build the Project ProviderModule1 using maven plugin
Project ParentProjectApplication
5. Load the maven dependency.
<dependency>
<groupId>com.demo.multimodule</groupId>
<artifactId>providerModule1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>app-to-import</classifier>
</dependency>
Autowire the MyService from project providerModule1
package com.multimodule.demo.parentProject.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.multimodule.providerModule1.service.MyService;
#Service
public class HomeService {
#Autowired
private MyService myService;
public String getHomeInfo() {
return "Home Info from Home service : "+myService.getInfoFromProperties();
}
}
Initially myservice was not getting loaded .Hence I added this step to main application class:
#SpringBootApplication(scanBasePackages= {"com.demo.multimodule.providerModule1.service",
"com.demo.multimodule.providerModule1.util"})
public class ParentProjectApplication {
}
Question 1 : Is this the only way using which I can autowire bean from a jar. If there is another way let me know.
I executed the Project ParentProjectApplication and it seem to work as expected.
Question 2 : Is it possible to autowire new yml property from Project ParentProjectApplication and make ServiceProperties bean of project ProviderModule1 utilise it.
you can try spring.factory to create beans.
refer the link below
https://docs.spring.io/spring-boot/docs/2.0.0.M3/reference/html/boot-features-developing-auto-configuration.html
i have a Spring Boot project which has some external packages i need to import as Beans in the main application.
So i have my main application in com.package.app package and some classes (among which some repositories) in com.package.commons package.
In order to take these beans i have my main class annotated as follows:
#SpringBootApplication
#ComponentScan({ "com.package.commons" ,"com.package.app"})
#EnableScheduling
#EnableAsync
public class EmanagerApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(EmanagerApplication.class, args);
}
}
But when i launch the application it may occur (not always but very ofter) that the start up fails with these kind of error:
Description:
Field repository in com.package.commons.service.BrandService required a bean of type 'com.package.commons.persistence.repository.BrandRepository' that could not be found.
Action:
Consider defining a bean of type 'com.package.commons.persistence.repository.BrandRepository' in your configuration.
My BrandRepository is annotated with #Repository and the service class with #Service
The really strange thing is that if i keep launching the app at the end it stars... but there is no reason for it...
If you're using JPA, you'll also need the #EnableJpaRepositories annotation.
Also consider to use #EnableTransactionManagement to enable declarative transaction handling.
E.g. use something like the following in the same package or a parent package where you have your JPA entities and JPA repositories (untested):
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
#Configuration
#EntityScan
#EnableJpaRepositories
#EnableTransactionManagement
public class HibernateConfig extends JpaBaseConfiguration {
public HibernateConfig(DataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
super(dataSource, properties, jtaTransactionManager, transactionManagerCustomizers);
}
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
#Override
protected Map<String, Object> getVendorProperties() {
return new HashMap<>();
}
}
And don't forget to annotate your #Service classes also with #Transactional.
If you confirm that the Application which with the startup method of this application is good, and confirm the #ComponentScan is good also. And the configuration file yaml or properties of JPA also good.
How about trying extends JPA Repository like this:
public class xxxResponsitory extends JpaRepository<T, E>{
...
}
Cause JpaRepository has already annotated with #Repository annotation, T means the type of Primary Key, I always use Integer or Long, autoboxing type. E means the main type of this repository.
Make an example:
Now we have an Entity type named User, the Primary key type of User is Long, I would write the repository like this:
public class UserRepository extends JpaRepository<Long, User>{
...
}
Don't need annotated anything, then, In the service class, #Autowried UserRepository, everything is good to run. But make sure the things that I talk at the start of my answer.
Hope this can help you.
I am trying to use Spring data and repositories in a Spring Boot application, but I have an error when compiling the project.
Here is my Entity :
package fr.investstore.model;
import javax.persistence.Id;
...
#Entity
public class CrowdOperation {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
#Enumerated(EnumType.STRING)
public RepaymentType repaymentType;
...
}
And the corresponding Repository:
package fr.investstore.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import fr.investstore.model.CrowdOperation;
public interface CrowdOperationRepository extends CrudRepository<CrowdOperation, Long> {
}
I use it in a WS controller, generating a repository through the Autowired annotation:
package fr.investstore.ws;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
...
#Controller
#EnableAutoConfiguration
public class SampleController {
#Autowired
private CrowdOperationRepository crowdOperationRepository;
#RequestMapping(path = "/", method = RequestMethod.GET)
#ResponseBody
public String getOperations(#RequestParam(required=true, defaultValue="Stranger") String name) {
crowdOperationRepository.save(new CrowdOperation());
return "Hello " + name;
}
}
And the code of the application:
package fr.investstore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import fr.investstore.ws.SampleController;
#SpringBootApplication
public class InvestStoreApplication {
public static void main(String[] args) {
SpringApplication.run(SampleController.class, args);
}
}
But when compiling the project I get:
APPLICATION FAILED TO START
Description: Field crowdOperationRepository in
fr.investstore.ws.SampleController required a bean of type
'fr.investstore.repositories.CrowdOperationRepository' that could not
be found.
Action: Consider defining a bean of type
'fr.investstore.repositories.CrowdOperationRepository' in your
configuration.
Woudn't Spring automatically generate a bean for the repository through the interface?
How can I resolve this?
EDIT: I also tried to put the Repository annotation (from org.springframework.stereotype.Repository) onto CrowdOperationRepository, but I got the same error
While creating a spring-boot application, we need to keep some point in our mind like
Always keep main class (class with `#SpringBootApplication annotation) on the top level package and other classes should lie under sub-packages.
Always mark your bean classes with proper annotation e.g. all repositories should be marked by #Repository annotation, all service implementation classes should be marked with #Service, other component classes should be marked by #Component, class which defines our beans should be marked as #Configuration
Enable the feature which you are using e.g. #EnableJpaRepositories, #EnableTransactionManagement, #EnableJpaAuditing, these annotations also provides functionality which let us define which package spring needs to scan.
So in your case, you need to mark InvestStoreApplication class with #EnableJpaRepositories annotation and CrowdOperationRepository with #Repository.
you have to tell your spring boot application to load JPA repositories.
copy this one to your application class
it will auto-scan your JPA repository and load it in your spring container even if you do not define your interface with #Repository it will wire that bean in your dependent class.
#EnableJpaRepositories(basePackages = { "fr.investstore.repositories" })
Thank to #JBNizet for his comment, that made it working.
I create this answer since he did not:
Replace SpringApplication.run(SampleController.class, args); with SpringApplication.run(InvestStoreApplication.class, args);. And remove the useless #EnableAutoConfiguration on your controller.
Annotating your entity class as shown as spring hint below to allow spring get a valid repository bean
Spring Data JPA - Could not safely identify store assignment for repository candidate interface com.xxxxx.xxxxRepository.
If you want this repository to be a JPA repository, consider annotating your entities with one of these annotations: javax.persistence.Entity, javax.persistence.MappedSuperclass (preferred),
or consider extending one of the following types with your repository: org.springframework.data.jpa.repository.JpaRepository.
2022-05-06 12:32:12.623 [ restartedMain] INFO [.RepositoryConfigurationDelegate:201 ] - Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces.
I get this exception when i try to use springboot + JPA + kotlin + maven
org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: #Bean method 'init' must not be private or final;
change the method's modifiers to continue
Offending resource: com.wirecard.kotlin.jpa.Application
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70)
at org.springframework.context.annotation.BeanMethod.validate(BeanMethod.java:50)
at org.springframework.context.annotation.ConfigurationClass.validate(ConfigurationClass.java:219)
at org.springframework.context.annotation.ConfigurationClassParser.validate(ConfigurationClassParser.java:528)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:307)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:239)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:254)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:94)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.wirecard.kotlin.jpa.ApplicationKt.main(Application.kt:50)
I followed the example in this link but it is built using Gradle
Springboot application for kotlin and JPA
The code consists of 3 classes
Class Customer
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
#Entity
class Customer(
val firstName: String,
val lastName: String,
#Id #GeneratedValue(strategy = GenerationType.AUTO)
val id: Long = -1) {
override fun toString(): String {
return "Customer(id=$id, firstName='$firstName', lastName='$lastName')"
}
}
Class CustomerController
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
#RestController
class CustomerController(val repository:CustomerRepository) {
#GetMapping("/")
fun findAll() = repository.findAll()
#GetMapping("/{lastName}")
fun findByLastName(#PathVariable lastName:String)
= repository.findByLastName(lastName)
}
Interface CustomerRepository
import org.springframework.data.repository.CrudRepository
interface CustomerRepository : CrudRepository<Customer, Long> {
fun findByLastName(lastName: String): Iterable<Customer>
}
From the log it looks like it's actually the 4th class, Application, that you're having a problem with. It says that the init method in that class shouldn't be private or final, your problem here would be the latter - functions and classes in Kotlin are final by default.
You can make the method non-final by marking it with the open keyword.
#Bean
open fun init(repository: CustomerRepository) = CommandLineRunner { ... }
You'll also have to mark your Application class with the open keyword.
#SpringBootApplication
open class Application { ... }
The reason these open keywords are not in the example is because it uses the kotlin-spring plugin (see in the build script), which opens up the classes and functions that Spring requires to be non-final.
You should be able to use the kotlin-spring plugin with Maven as well, if you don't want to manually make your classes open. The instructions for doing so are right above the Gradle instructions, at the end of the chapter about the all-open plugin. You just have to include the code that's there, and replace <plugin>all-open</plugin> with <plugin>spring</plugin>, as the comment there describes.
I'm developing a Spring Boot application which uses some Spring Data Repository interfaces:
package test;
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
private BookRepository repository;
. . .
}
I can see that the BookRepository interface (which follows here) can only be injected if it's in the same package as the Application class:
package test;
public interface BookRepository extends MongoRepository<Book, String> {
public Book findByTitle(String title);
public List<Book> findByType(String type);
public List<Book> findByAuthor(String author);
}
Is there any Spring Boot annotation I can apply on my classes to be able to find the BookRepository in another package ?
Use a Spring #ComponentScan annotation alongside the SpringBoot #SpringBootApplication and configure a custom base package (you can either specify a list of package names or a list of classes whose package will be used), so for example
#SpringBootApplication
#ComponentScan(basePackages = {"otherpackage", "..."})
public class Application
or
#SpringBootApplication
#ComponentScan(basePackageClasses = {otherpackage.MyClass.class, ...})
public class Application
or since Spring 1.3.0 (Dec. 2016), you can directly write:
#SpringBootApplication(scanBasePackageClasses = {otherpackage.MyClass.class, ...})
public class Application
Note that component scan will find classes inside and below the given packages.
Good to verify the scopes of classes kept in different packages by using #ComponentScan annotation in Spring boot startup custom class.
Also add #Component in modal classes being used to allow framework accessing the classes.
Example is kept at
http://www.javarticles.com/2016/01/spring-componentscan-annotation-example.html