spring populating configuration properties, am unable to do so - spring-boot

i so im trying to populate a configuration class with a boolean value and i keep getting the below
Parameter 0 of constructor in example.demo.config required a bean of type 'java.lang.Boolean' that could not be found.
classes:
#EnableFeignClients
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#Configuration
#ConfigurationProperties
#Builder
#Getter
#Setter
public class config {
#Value("${enabled}")
private Boolean enabled;
#Value("#$'{values}'.split(',')")
private List<String> values;
application.properties
enabled=true
values=3,4,5,6,7

There are several options:
Remove #Builder from the config-class. Because #Builder forces an all-argument constructor and Spring, using #Value, needs a no-argument constructor.
Use #Value in the constructor.
#Configuration
#Builder
#Getter
#Setter
class Config {
private Boolean enabled;
private List<String> values;
public Config(#Value("${enabled}") Boolean enabled, #Value("${values}") List<String> values) {
this.enabled = enabled;
this.values = values;
}
}
Note that spring is smart enough to convert 3,4,5,6,7 to a list of numbers/strings
Looking back at option one... there is actually a third option:
#Configuration
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
class Config {
#Value("${enabled}")
private Boolean enabled;
#Value("${values}")
private List<String> values;
}
And for completeness, without #Value
#EnableConfigurationProperties({Config.class})
#ConfigurationProperties(prefix = "prefix"), prefix can be empty
#ConstructorBinding tell spring to use constructor binder
#SpringBootApplication
#EnableConfigurationProperties({Config.class}) // <-- 1
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#ConfigurationProperties(prefix = "prefix") // <-- 2
#ConstructorBinding // <-- 3
#Builder
#Getter
#Setter
class Config {
private Boolean enabled;
private List<String> values;
}

Related

How can i fix this Exception? -> Caused by: java.lang.IllegalArgumentException: Not a managed type:

i have got this Exception
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dumpController' defined in file [...\tech\backend\webapplication\com\controller\DumpController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'dumpService' defined in file [...\tech\backend\webapplication\com\service\DumpService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'dumpRepository' defined in tech.backend.webapplication.com.repo.DumpRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Not a managed type: class tech.backend.webapplication.com.model.Dump
...
Caused by: java.lang.IllegalArgumentException: Not a managed type: class tech.backend.webapplication.com.model.Dump
...
Process finished with exit code 1
Here are my classes:
MainClass
package tech.backend.webapplication;
#SpringBootApplication
public class WebapplicationApplication {
public static void main(String[] args) {
SpringApplication.run(WebapplicationApplication.class, args);
}
}
ModelClass:
package tech.backend.webapplication.com.model;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Entity
public class Dump implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String email;
}
Repository:
package tech.backend.webapplication.com.repo;
#Repository
public interface DumpRepository extends JpaRepository<Dump, Long> {
void deleteDumpById(Long id);
Optional<Dump> findDumpById(Long id);
}
Service:
package tech.backend.webapplication.com.service;
#Service
#RequiredArgsConstructor
#Slf4j
#Transactional
public class DumpService {
private final DumpRepository dumpRepository;
public Dump addDump(Dump dump) {
dump.setName("Johannes");
dump.setEmail("Johannes#mail.com");
return dumpRepository.save(dump);
}
public List<Dump> getAllDumps() {
return dumpRepository.findAll();
}
public Dump getDumpById(Long id) {
return dumpRepository.findDumpById(id)
.orElseThrow(() -> new DumpNotFoundException("Dump by id " + id + "was not found"));
}
public Dump updateDump(Dump dump) {
return dumpRepository.save(dump);
}
public void deleteDump(Long id) {
dumpRepository.deleteDumpById(id);
}
}
Controller:
package tech.backend.webapplication.com.controller;
#RestController
#RequestMapping("/dump")
#RequiredArgsConstructor
#Slf4j
public class DumpController {
private final DumpService dumpService;
#GetMapping("/all")
public ResponseEntity<List<Dump>> getAllDumps() {
List<Dump> dumps = dumpService.getAllDumps();
return new ResponseEntity<>(dumps, HttpStatus.OK);
}
#GetMapping("/find/{id}")
public ResponseEntity<Dump> getDumpById(#PathVariable("id") Long id) {
Dump dump = dumpService.getDumpById(id);
return new ResponseEntity<>(dump, HttpStatus.OK);
}
#PostMapping("/add")
public ResponseEntity<Dump> addDump(#RequestBody Dump dump) {
Dump newDump = dumpService.addDump(dump);
return new ResponseEntity<>(newDump, HttpStatus.CREATED);
}
#PutMapping("/update")
public ResponseEntity<Dump> updateDump(#RequestBody Dump dump) {
Dump updatedDump = dumpService.updateDump(dump);
return new ResponseEntity<>(updatedDump, HttpStatus.CREATED);
}
#DeleteMapping("/delete/{id}")
public ResponseEntity<?> deleteDump(#PathVariable("id") Long id) {
dumpService.deleteDump(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}
The packages are as follows:
java
tech.backend.application
com
controller
exception
model
repo
service
WebapplicationApplication (class)
ressources
Can somebody help me to fix this error?
I would appreciate that :)
Thanks
Every time I start the application, this exception is the output
Spring Boot's auto-configuration probably cannot find your entity Dump.
Add the #EntityScan annotation to your application class or a configuration class, for example:
package tech.backend.webapplication;
#SpringBootApplication
#EntityScan("tech.backend.webapplication.com.model")
public class WebapplicationApplication {
public static void main(String[] args) {
SpringApplication.run(WebapplicationApplication.class, args);
}
}
On multi-modules this issue can happen,you can do on your main class,
#SpringBootApplication
#ComponentScan(basePackages = {"tech.backend.webapplication.*"})
public class WebapplicationApplication {
public static void main(String[] args) {
SpringApplication.run(WebapplicationApplication.class, args);
}
}

Why is a bean created twice in test when using #PostConstruct?

I have a configuration class that uses a properties file and it works properly.
Now I want to test that code and I have to recognize that the method annotated with #PostConstruct is run twice during the test. (In debug mode I can see that the for-loop is conducted twice.)
The configuration class:
#Slf4j
#RequiredArgsConstructor
#Configuration
#ConfigurationPropertiesScan("com.foo.bar")
public class MyConfig {
private final MyProperties myProperties;
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
void init() {
Objects.requireNonNull(myProperties, "myProperties may not be null");
for (final MyProperties.MyNestedProperty nested : myProperties.getApps()) {
log.info("xxx {} created.", nested.getName());
applicationContext.registerBean(nested.getName(), MyContributor.class, nested);
}
}
}
The used properties class:
#Slf4j
#Data
#Validated
#ConfigurationProperties(prefix = MyProperties.CONFIG_PREFIX)
public class MyProperties {
public static final String CONFIG_PREFIX = "xxx";
#Valid
#NestedConfigurationProperty
private List<MyNestedProperty> apps;
#Data
public static class MyNestedProperty {
#NotNull
#NotEmpty
private String abc;
private String xyzzy;
#NotNull
#NotEmpty
private String name;
}
}
My attempt with the test class:
#ExtendWith(SpringExtension.class)
#RequiredArgsConstructor
#ContextConfiguration(classes = MyConfigTest.MyTestConfiguration.class)
class MyConfigTest {
#MockBean
MyProperties myProperties;
ApplicationContextRunner context;
#BeforeEach
void init() {
context = new ApplicationContextRunner()
.withBean(MyProperties.class)
.withUserConfiguration(MyConfig.class)
;
}
#Test
void should_check_presence_of_myConfig() {
context.run(it -> {
assertThat(it).hasSingleBean(MyConfig.class);
});
}
// #Configuration
#SpringBootConfiguration
// #TestConfiguration
static class MyTestConfiguration {
#Bean
MyProperties myProperties() {
MyProperties myProperties = new MyProperties();
MyProperties.MyNestedProperty nested = new MyProperties.MyNestedProperty();
nested.setName("xxx");
nested.setAbc("abc");
nested.setXyz("xyz");
myProperties.setApps(List.of(nested));
return myProperties;
}
}
}
Why does this happen and how can I prevent this behaviour?

How to #Autwired MessageSource in spring into Entity class correctly?

I have the following entity in spring boot application:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Audited
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#Table(name = "currency", catalog = "currency_db")
public class Currency implements java.io.Serializable {
#Autowired
Messages messages;
As for message, it just a container of spring MessageSource here it is:
#ApplicationScope
#Component
#Slf4j
public class Messages {
#Autowired
private MessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
accessor = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
log.info("Messages initialized");
}
public String get(String code) {
return accessor.getMessage(code);
}
}
I'm getting the following error when run mvn clean install. Any idea what I'm missing here?
org.hibernate.MappingException: Could not determine type for: com.company.currencyservice.Messages, at table: currency, for columns: [org.hibernate.mapping.Column(messages)]
It's looks like hibernate think it's a column. Thanks.
Entities are not Spring beans and therefor you cannot use dependency injection in entities.
If you want to access a Spring bean from within an entity you can use a helper class like this:
#Service
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
public static Object bean(String name) {
return context.getBean(name);
}
#Override
public void setApplicationContext(#SuppressWarnings("NullableProblems") ApplicationContext ac) {
context = ac;
}
}
Then you can use ApplicationContextProvider.getBean(Messages.class) to get access to the Messages.

Spring JPA custom repository different packages

I'm developing a spring boot application and i'm running into an issue here. I want to have separate packages for my RepositoryImpl, RepositoryCustom and Repository classes but when i separate the packages im getting this error:
Caused by:
org.springframework.data.mapping.PropertyReferenceException: No
property customMethod found for type Demo!
It only works when i put my RepositoryImpl, RepositoryCustom and Repository classes into the same package. I've tried #EnableJpaRepositories("com.example.demo.persist") but still not working.
Is there a way i can achieve this?
Here's my code:
DemoApplication.java
#SpringBootApplication
#EnableJpaRepositories("com.example.demo.persist")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
DemoController.java
#RestController
public class DemoController {
#Autowired
DemoService demoService;
#RequestMapping("/test")
public String getUnidades() {
demoService.customMethod();
return "test";
}
}
DemoRepositoryCustom.java
public interface DemoRepositoryCustom {
void customMethod();
}
DemoRepositoryImpl.java
public class DemoRepositoryImpl implements DemoRepositoryCustom {
#Override
public void customMethod() {
// do something
}
}
DemoRepositoryCustom.java
public interface DemoRepository extends JpaRepository<Demo, Long>, DemoRepositoryCustom {
}
Demo.java
#Entity
public class Demo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", columnDefinition = "bigint")
private int id;
#NotEmpty
#Column(name = "name", columnDefinition = "VARCHAR(60)", length = 60, unique = false, nullable = false)
private String name;
// ...
DemoService.java
#Service
#Transactional
public class DemoService {
#Autowired
DemoRepository demoRepository;
public void customMethod() {
demoRepository.customMethod();
}
}
application.properties
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.url=jdbc:mysql://localhost:3306/demo?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
Autodetection of custom implementations work only in packages below the one declaring the Repository.
But you can make your implementation a bean with the name matching the required class name.
That would be demoRepositoryImpl in your case.
See the documentation for details.
Actually your package hierarchy is not in right order.
Make it like this :
com.example.demo.repository
com.example.demo.repository.custom
com.example.demo.repository.custom.impl
And it will work.

Spring Boot not autowiring #Repository

I'm trying to configure a datasource with Spring Boot but I'm getting org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.myapp.repository.UserRepository com.mycompany.myapp.service.AuthenticationServiceImpl.userRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.myapp.repository.UserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
These is my project structure:
Main Class:
package com.mycompany.myapp;
#ComponentScan(basePackageClasses = {com.mycompany.myapp.domain.user.User.class,
com.mycompany.myapp.repository.UserRepository.class,
com.mycompany.myapp.service.AuthenticationServiceImpl.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Domain Class:
package com.mycompany.myapp.domain.user
#Entity
public class User {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String lastName;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String email;
public User() {}
public User(String email, String password){
this.email = email;
this.password = password;
}
}
Repository:
package com.mycompany.myapp.repository;
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName);
}
Controller
package com.mycompany.myapp.service;
#RestController
public class AuthenticationServiceImpl implements AuthenticationService {
#Autowired
private UserRepository userRepository;
#RequestMapping("/add")
public User add(){
User user = new User();
user.setName("Juan");
user.setLastName("Sarpe");
user.setEmail("email#gmail.com");
userRepository.save(user);
return user;
}
}
application.properties
spring.datasource.url:jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
I guess my app is not detecting my #Repository annotation on UserRepository. As far as I know, Spring Boot will automatically set my class as #Repository because it is extending CrudRepository. What am I doing wrong? (Notice that my Application class is on top of packages hierarchy).
In main class of spring boot you have to use this below annotation :
#SpringBootApplication
#ComponentScan(basePackages = "basepackage")
#EntityScan(basePackages ="basepackage")
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "basepackage")
In Repository layer use below annotation :
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Transactional
#Repositor
If you have any service layer then use below annotation in the implementation class:
import org.springframework.stereotype.Service;
#Service
Have you tried #EnableJpaRepositories in your configuration ?
The standard way to configure is to create a base marker repository interface and provide that in the component scan.
public interface RepositoryPackage {
}
Keep the interface RepositoryPackage in the same package as UserRepository.
#ComponentScan(basePackageClasses= "RepositoryPackage.class")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Resources