Spring Boot defining bean in configuration problem - java

I'm working on a project on my sparetime, on this project I have been asked to work with Spring Boot. I'm not familiar with Spring Boot from before, and I have tried searching here on stackoverflow and Google, but I can't seem to understand how the different solutions for my problem works.
First of all, this is my error message:
Parameter 0 of constructor in com.project.example.controller.VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
Action:
Consider defining a bean of type 'com.project.example.dao.VerverDao' in your configuration.
After some reading, I understood that this could be because of Spring Boot don't scan this class / interface. So I tried to add ComponentScan, with no luck.
I tried to convert VerverDao from interface to class and register a bean with bean annotation. Still no luck. I tried to move the VerverDao from the dao package to the root package (the same as the Main class) and still no luck.
So if someone could please help me understand the error message, it would make my day.
This is my structure:
This is my code:
Probably some of the annotation is wrong as well, since I'm not used to Spring Boot, in advance thanks for correcting me on the use of these
It is also worth mentioning that I'm using Lombok as well on this project.
Main.java
#ComponentScan("com.gambinomafia")
#SpringBootApplication
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
new Main().configure(new SpringApplicationBuilder(Main.class)).run(args);
}
}
Configuration.java
#Component
public class Configuration extends ResourceConfig {
public Configuration() {
register(VerverResourceImpl.class, VerverResource.class);
register(VerverController.class);
register(VerverDao.class);
}
}
VerverResource.java
#Resource
#Path("verver")
public interface VerverResource {
#GET
#Path("/{userid}")
#Produces(MediaType.APPLICATION_JSON)
String getRefferingUrl(#PathParam("userid") int userid);
}
VerverResourceImpl.java
#AllArgsConstructor(onConstructor = #__({#Inject}))
public class VerverResourceImpl implements VerverResource {
private VerverController controller;
#Override
public String getRefferingUrl(int userid) {
log.info("Collection reciever url for user id: {}", userid);
return controller.getRefferingUrl(userid);
}
}
VerverController.java
#Controller
#AllArgsConstructor
public class VerverController {
private VerverDao ververDao;
public String getRefferingUrl(int userid) {
User user = ververDao.getUsername(userid);
if (user.getUsername().isEmpty()) {
throw new NotFoundException("Did not find any user with id " + userid);
}
return "<url-to-site>/?verv=" + user.getUsername();
}
}
VerverDao.java
#AllArgsConstructor
public class VerverDao {
#Value("spring.datasource.url")
private String dbcon;
public User getUsername(int userid) {
Jdbi jdbi = Jdbi.create(dbcon);
return jdbi.withHandle(handle -> handle.createQuery(
"SELECT id, brukernavn FROM t_user WHERE id = :id")
.bind("id", userid)
.mapToBean(User.class)
.findOnly());
}
}
Feel free to ask for more information, if there is missing some information in the topic. I will try to answer as fast as possible.

First at all, you're setting a #ComponentScan with a wrong package in your Application class.
#ComponentScan("com.gambinomafia")
#SpringBootApplication
And, according to the picture, it has to be:
#ComponentScan("com.project.example")
#SpringBootApplication
EDIT: the use of #ComponentScan by #M.Deinum
Because of the Application Class is in the root package and #SpringBootApplication already contains #ComponentScan, It isn't needed to declare #ComponentScan.
Second, instead of use a DAO you can use Repositories. There is more information here: Spring Boot Repositories.
Third, to inject your objects you can use #Autowired over the constructor.
#Controller
public class VerverController
private VerverDao ververDao;
#Autowired
public VerverController(VerverDao ververDao) {
this.ververDao = ververDao;
}
}
There is more information here.

Log clearly says
VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
It means there is no bean of type com.project.example.dao.VerverDao
Add #Repository on top of VerverDao to resolve the issue.
#Repository
#AllArgsConstructor
public class VerverDao {
}
Note: Ensure VerverDao is in component scanning path as per your package structure.

Related

Spring Boot - How to read properties from multiple custom yml

We are upgrading the spring boot version from 1.3.0.RELEASE to 2.3.12.RELEASE.
As per the old version, yml files were read using the following code snippet
#Configuration
#ConfigurationProperties(locations = "classpath:/config/myconf-source.yml")
public class MyConfigProperties {
private String configSource;
public String getConfigSource() {
return configSource;
}
public void setConfigSource(String configSource) {
this.configSource = configSource;
}
}
Config files in src/main/resources/config/
myconf-source.yml
news-source.yml
conf-mapping.yml
Content in myconf-source.yml
configSource: "TEST"
Corresponding Test Class
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
#EnableAutoConfiguration
#SpringApplicationConfiguration(classes = SampleApplication.class)
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
#ConfigurationProperties(locations = "classpath:**/config/**")
public class MyConfigPropertiesTest {
#Autowired
private MyConfigProperties myConfigProperties;
#Test
public void testMyConfigProperties() {
String config = myConfigProperties.getConfigSource();
Assert.assertEquals(config, "TEST");
}
}
After changing to the new version, it throws an error Cannot resolve method 'locations'.
If I remove locations attribute how spring will know the class MyConfigProperties has to read myconf-source.yml
Also while running the test class, NullPointerException is thrown as myConfigProperties.getConfigSource(); becomes null.
I have tried various solutions posted but no luck,
Can anyone suggest how to make it work?
Thanks
#Configuration should be used if in that class you define beans with #Bean.
If not then remove it from there.
Also #Configuration does not make this class a bean to be autowired in the test that you require it to be.
If you want MyConfigProperties to be available for autowiring then you also need
#EnableConfigurationProperties(MyConfigProperties.class). This will make sure that this class is available as a spring bean in the application context.
So it would be
#PropertySource("classpath:/config/myconf-source.yml")
#ConfigurationProperties()
#EnableConfigurationProperties(MyConfigProperties.class)
public class MyConfigProperties {
private String configSource;
public String getConfigSource() {
return configSource;
}
public void setConfigSource(String configSource) {
this.configSource = configSource;
}
}
You can use #PropertySource annotation to read the yml file , you can read the below article :
https://www.baeldung.com/properties-with-spring

Spring Boot Application not registering #Repository

I'm creating a simple SpringBoot application with spring-data-jpa for learning purposes.
My problem is when I try to #Autowire a #Repository the application always fails to start with the error:
APPLICATION FAILED TO START
***************************
Description:
Field pedidoRepository in com.pedidos.services.PedidoService required a bean of type 'com.pedidos.repositories.PedidoRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.pedidos.repositories.PedidoRepository' in your configuration.
All the answers that i have found so far tells me to do something that is already done in my application. I'm probably missing something and I can't find out what it is.
This is how my application is now (imports are omitted):
Application:
package com.pedidos;
#SpringBootApplication
public class PedidosApplication {
public static void main(String[] args) {
SpringApplication.run(PedidosApplication.class, args);
}
}
Repository:
package com.pedidos.repositories;
#Repository
public abstract class PedidoRepository implements JpaRepository<Pedido, UUID> {
}
Service:
package com.pedidos.services;
#Service
public class PedidoService {
#Autowired
private PedidoRepository pedidoRepository;
public Optional<Pedido> findById(UUID id){
return pedidoRepository.findById(id);
}
public Pedido save(Pedido pedido){
return pedidoRepository.save(pedido);
}
}
Controller:
package com.pedidos.controllers;
#Controller("/pedido")
public class PedidoController {
#Autowired
private PedidoService pedidoService;
#GetMapping("/{id}")
public Pedido get(#PathVariable(name = "id") UUID id){
return pedidoService.findById(id).get();
}
}
Here is my Project structure
If do not inject the repository the application runs fine.
The entire code is in this GitHub repo: https://github.com/brunomokan/pedidos
Like what ILya Cyclone say. A Spring-Data Repository should be an interface which get a proxy at runtime. Something like this. Its fine if you extend from another interface.

Spring Crud Repository - Unsatisfied dependency expressed - Cant inject model

i seem to be unable to get Spring to recognize the native CrudRepository and use it, because spring isn not able to inject / use the actual class that my generic CrudRepository needs to implement when i put it in a different package than the one with the main method.
My Project structure is pretty straight forward.
Leaving the structure like this works just fine!
I want however Author to be inside the model package, like this:
However Spring always throws the error:
Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'authorRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authorRepository' defined in service.AuthorRepository defined in #EnableJpaRepositories declared on DemoApplication: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class model.Author
I definately dont want to use a configuration through an application.properties.xml file. I want it to be programmatically configured within java code.
The Author.java :
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "authors")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
}
The AuthorRepository that implements the CrudRepository:
#Repository
public interface AuthorRepository extends CrudRepository<Author, Integer> {
}
If it is of any importance here is the Config class where i define my DataSource. The #Bean with Author seems not important, since it works without it too when i leave the Author inside the com.example.demo package.
#Configuration
public class Config {
#Bean
public DataSource dataSource(){
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:mysql://localhost:3306/sks");
dataSourceBuilder.username("sks");
dataSourceBuilder.password("technikum1");
return dataSourceBuilder.build();
}
#Bean
public Author author(){
return new Author();
}
}
And finally my Main method:
#SpringBootApplication
#ComponentScan(basePackages = {"config"})
#EnableJpaRepositories(basePackages = {"service"})
public class DemoApplication implements CommandLineRunner {
#Autowired
private AuthorRepository authorRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
#Transactional
public void run(String... args) throws Exception {
Iterable<Author> authors = authorRepository.findAll();
System.out.println(authors);
}
}
I tried annotating the AuthorRepository with a #ComponentScan(basePackages = {"model"}) and annotated the Author.java with #Component because i thought it might not recognize it as bean or something if i put it in another package ( which would be strange anyway since i dont need the component annotation when i leave it in the main package) but nothing worked so far.
Generally struggling hard with project structure and Spring....
Also i have tried to change the #ComponentScan(basePackages = {"config"}) in DemoApplication to #ComponentScan(basePackages = {"config","model"}).
Nothing worked so far !
I need some help ...

SpringBoot - Register a bean before #Component's get scanned

I have a component Login that depends on ValidatorService. ValidatorService is being injected/autowired in the Login constructor. ValidationServiceImpl is provided by an external API, so I can't just annotate it as #Service.
#Component
class Login {
#Autowire
public Login (ValidatorService validator) {
}
}
#SpringBootApplication
public class Starter {
public static void main(String[] args)
{
SpringApplication.run(Starter.class, args);
}
}
I'm looking for a way to register ValidatorService as a bean before #Components get scanned. Is there a way to get ApplicationContext instance before starting the application?
SpringBoot 2.0.4.RELEASE
UPDATE
I need to pass a validationId that I'll get from main(args) to this external API.
public static void main(String[] args) {
String validationId = args[0];
ValidatorService service = ExternalValidationAPI.getValidationServiceImp(validationId);
}
You should be able to declare it as a bean as such in one of your configuration classes:
#Bean
public ValidatorService validatorService(){
return new ValidatorServiceImpl();
}
This will then autowire in the ValidatorService implementation class at the point it is needed. This method needs to go in an #Configuration class (your Starter class is one).
There's a good example of how to do this here.
I believe you can solve your problem with the help of the #Configurable annotation.
Annotate your Login class with #Configurable instead of #Componenet, and when the ValidatorService object becomes available, you can initiate the Login object with it.
You need to define a ValidationService bean :
#Configuration
public class ValidationServiceConfig {
#Bean
public ValidationService validationService(#Value("${validationId}") String validationId) {
return new ValidationServiceImpl(validationId);
}
}
and run the program this way : java -jar program.jar --validationId=xxx
I solved my problem creating a Configuration class and declaring a Bean to handle the instantiation of the external service that will be injected later (as some people have suggested). In order to retrieve the program arguments I autowired DefaultApplicationArguments to retrieve program arguments with getSourceArgs():
#Configuration
public class ValidatorConfig {
#Autowired
DefaultApplicationArguments applicationArguments;
#Bean
public ValidatorService validatorService()
{
String validationId = applicationArguments.getSourceArgs()[0];
return ExternalValidationAPI.getValidationServiceImp(validationId);
}

Spring boot #Autowired can't initialise class

I have following class as:-
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
public class DemoSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApp.class, args);
}
}
I have following class as:-
#Service
public class TopicService {
// if I comment out following autowired, then it is ok.
#Autowired
private TopicRepository topicRepository;
}
I have following interface as:-
public interface TopicRepository extends CrudRepository<Topic, String> {
}
I have following class as:-
#Entity
public class Topic {
#Id
private String id;
private String name;
private String description;
public Topic() {
}
}
I got following error when try to execute:-
APPLICATION FAILED TO START
Description:
Field topicRepository in com.ma.demospringboot.service.TopicService
required a bean of type
'com.ma.demospringboot.repository.TopicRepository' that could not be
found.
Action:
Consider defining a bean of type
'com.ma.demospringboot.repository.TopicRepository' in your
configuration.
Spring container is not finding your repository classes during the scan, add #EnableJpaRepositories to explicitly specify the packages of where your repository classes exist, as shown below:
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
#EnableJpaRepositories("com.ma.demospringboot.repository")
#EntityScan(basePackages = "com.ma.demospringboot.domain")
public class DemoSpringBootApp {
//your current code here
}
UPDATE1:
Not a managed type: class com.ma.demospringboot.domain.Topic
Now, your Topic entity class not found, so you need to #EntityScan(basePackages = "com.ma.demospringboot.domain") to scan the entity classes (as show above).
UPDATE2:
I did exactly as you suggested, but NOT working
There is a problem with the way that you are packaging the classes, double check on that, also ensure that the latest classes have been compiled/built & used by the server.
Your Spring container is unable to find and identify your JPA repositories.
Add #EnableJpaRepositories("com.ma.demospringboot.repository") on your DemoSpringBootApp class
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
#EnableJpaRepositories("com.ma.demospringboot.repository")
public class DemoSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApp.class, args);
}
}
add following code in your ApplicationContext.xml
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

Categories