Ihave property class:
#Getter
#Setter
#Component
#ConfigurationProperties(prefix = "my-api")
public class MyApiProperties {
...
private MyClient myClient;
#Getter
#Setter
public static class MyClient {
private String host;
private long connectionTimeout;
private long receiveTimeout;
}
}
I can config it:
my-api:
my-client:
host: http://1...
connection-timeout: 30000
receive-timeout: 60000
And I can Inject it:
#Value("${my-api.my-client.host}")
private String host;
But can I inject full object like this?
#Value("${my-api.my-client}")
private MyClient myClient;
Related
With an application.properties like that
application:
api:
clients:
api1:
url: http://url1
api2:
url: http://url2
basicAuth:
username: user2
password: password2
I can do
#Configuration
#ConfigurationProperties(prefix = "application.api")
#Data
public class ApiProperties {
private Map<String, Client> clients;
#Data
public static class Client {
private String url;
private BasicAuth basicAuth;
}
#Data
public static class BasicAuth {
private String username;
private String password;
}
}
And it is working.
But is there a way of retrieving only one client ? So In place of
private Map<String, Client> clients;
I'd like to have something like
#Value("${application.api.clients['api1']}")
private Client client1;
I tried multiple ways of writing it but I always have Could not resolve placeholder...
Is there a solution ?
Looks like this is not possible with nested properties or hierarchal properties.
#Value("${application.api.clients['api1']}")
private Client client1;
But you can try this if you want to retrieve only one client.
#Configuration
#ConfigurationProperties(prefix = "application.api.clients")
#Data
public class ApiProperties {
private Client api1;
#Data
public static class Client {
private String url;
private BasicAuth basicAuth;
}
#Data
public static class BasicAuth {
private String username;
private String password;
}
}
its my first time crating api in spring boot, i'm trying to create transaction api. when i'm running the application i'm getting this error
Description:
Parameter 0 of constructor in TransactionService.transactionService.modal.TransactionRequest required a bean of type 'int' that could not be found.
Action:
Consider defining a bean of type 'int' in your configuration.
Modal package:
TransactionEntity
#Getter
#Setter
#Builder
#Entity
public class TransactionEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int transactionId;
#NotNull
#Column(unique = true)
private UUID externalId;
#NotNull
private int userId;
#NotNull
private int merchantId;
#NotNull
private int clientReferenceId;
#NotNull
private double amount;
#Enumerated(EnumType.STRING)
#NotNull
private TransactionStatus status;
#NotNull
private String createdBy;
private String updatedBy;
#NotNull
private LocalDateTime createdAt;
#NotNull
private LocalDateTime updatedAt;
}
TransactionRequest
#Component
#Data
#Builder
public class TransactionRequest {
private int userId;
private int merchantId;
private int clientReferenceId;
private double amount;
private String createdBy;
}
TransactionResponse
#Component
#Data
#Builder
public class TransactionResponse {
private int userId;
private int merchantId;
private int clientReferenceId;
private double amount;
private LocalDateTime createdAt;
private TransactionStatus status;
}
TransactionDao
#Component
// Dao class
public class TransactionDao {
#Autowired
TransactionRepository transactionRepository;
TransactionEntity transactionEntity;
public TransactionResponse createTransaction(TransactionRequest transactionRequest){
LocalDateTime cuurentTime = LocalDateTime.now();
transactionEntity.builder().userId(transactionRequest.getUserId())
.merchantId(transactionRequest.getMerchantId())
.clientReferenceId(transactionRequest.getClientReferenceId())
.amount(transactionRequest.getAmount())
.createdBy(transactionRequest.getCreatedBy())
.createdAt(cuurentTime)
.updatedAt(cuurentTime)
.externalId(UUID.randomUUID())
.status(TransactionStatus.CREATED);
transactionRepository.save(transactionEntity);
return TransactionResponse.builder().status(transactionEntity.getStatus())
.createdAt(transactionEntity.getCreatedAt()).build();
}
}
TransactionService
#Service
public class TransactoinService {
#Autowired
public TransactionDao transactionDao;
public TransactionResponse createTransaction(TransactionRequest transactionRequest){
return transactionDao.createTransaction(transactionRequest);
}
}
TransactionController
#RestController
public class TransactionController {
#Autowired
TransactoinService transactoinService;
#PostMapping
TransactionResponse createTransaction(#RequestBody TransactionRequest transactionRequest){
return transactoinService.createTransaction(transactionRequest);
}
}
The TransactionRequest is annotated as #Component so spring boot autoscan will try to create a #Bean out that class.
It is also annotated with #Data so at the time of creating the bean Spring boot is trying to inject other beans as arguments into the all args constructor, and it is not finding an "int" bean to inject into the constructor.
I am guessing that the transaction response should not be a #Component or at least not a Singleton bean.
You should not create your POJO classes as a Spring Bean. Remove #Component annotation in your TransactionRequest and TransactionResponse POJO classes.
I have a super Entity class like this:
#Getter
#Setter
#NoArgsConstructor
public class GenericEntity {
#Id
private Long id;
#JsonIgnore
#CreatedBy
private Long createdBy;
#JsonIgnore
#CreatedDate
private Long createdDate;
#JsonIgnore
#LastModifiedBy
private Long updatedBy;
#JsonIgnore
#LastModifiedDate
private Long updatedDate;
#JsonIgnore
#Version
private Integer version = 0;
}
and a Role class extends from GenericEntity like this:
#Getter
#Setter
#NoArgsConstructor
public class Role extends GenericEntity {
private String name;
private String desc;
private Integer sort;
}
And after that I have interface RoleRepo like this:
#Repository
public interface RoleRepo extends ReactiveCrudRepository<Role, Long>;
In Router function, I have 2 handler methods
private Mono<ServerResponse> findAllHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(roleRepo.findAll(), Role.class);
}
private Mono<ServerResponse> saveOrUpdateHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(request.bodyToMono(Role.class).flatMap(role -> {
return roleRepo.save(role);
}), Role.class);
}
The method findAllHandler works fine, but the saveOrUpdateHandler throw exception like this:
java.lang.IllegalStateException: Required identifier property not found for class org.sky.entity.system.Role!
at org.springframework.data.mapping.PersistentEntity.getRequiredIdProperty(PersistentEntity.java:105) ~[spring-data-commons-2.2.0.M2.jar:2.2.0.M2]
at org.springframework.data.r2dbc.function.convert.MappingR2dbcConverter.lambda$populateIdIfNecessary$0(MappingR2dbcConverter.java:85) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
But when I move
#Id
private Long id;
from GenericEntity class to Role class, the two methods work fine.
Are there any Annations #MappedSuperclass/JPA in Spring Reactive Data like that
I wish the id field in GenericEntity for all extends class
Thanks for your help
Sorry, my English so bad
I had a similar problem and after some search, I didn't find an answer to your question, so I test it by writing code and the answer is spring data R2DBC doesn't need #Mappedsuperclass. it aggregates Role class properties with Generic class properties and then inserts all into the role table without the need to use any annotation.
I have a problem with Spring boot.
I created Entity and Repository, but method findByName in Repository isn't work.
My url:
http://localhost:8080/student/search/findByName?name=Artem
In Google chrome: localhost not found, but search is mapped.
Entity:
#Getter #Setter
#Entity #Table(name = "Student")
public class Student extends BaseEntity{
private String name;
private String dateOfBirthDay;
private String sex;
private String phoneNumber;
}
BaseEntity:
#Getter
#Setter
#MappedSuperclass
public class BaseEntity {
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE) #Column protected Long id;
My Repository:
#RepositoryRestResource(collectionResourceRel = "student", path = "student")
public interface StudentRepository extends PagingAndSortingRepository<Student, Long> {
Student findByName(#Param("name") String name);
}
Application:
#SpringBootApplication
#EnableTransactionManagement
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application.yaml:
spring:
application:
name: students
datasource:
driverClassName: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/students
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: update
server:
port: 8080
I recommend you to create a resource class, works like controller. Here a simple example:
#RestController
#RequestMapping("/yourPath") //students, whatever
public class StudentsResource {
#Autowired
private StudentRepository studentRepository;
//type media that you want to show (json, xml...in this case is JSON)
#RequestMapping(method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
// <Student> is the entity, object
#RequestMapping(value = "/yourPath/{studentName}")
public ResponseEntity<Student> findByName(#pathVariable("studentName") String name) {
Student student = studentRepository.findByName(name);
if(student == null){
//handler your own exception here
}
//show the student as json object
return ResponseEntity.status(HttpStatus.OK).body(student);
}
Note: that's the resource class. But your problem is about localhost, so if you are using Spring Boot, see if your "application.properties" is correct. Here my example:
spring.datasource.url=jdbc:mysql://localhost:3306/yourDataBase
spring.datasource.username=yourUser
spring.datasource.password=yourPassword
spring.jpa.hibernate.ddl-auto=update //makes the spring create the database automatic!
We are working on a Spring Boot API.
We use #RestRepositoryResource annotation to generate endpoints.
#RepositoryRestResource(collectionResourceRel = "datarow", path = "datarow")
public interface DataRowRepository extends MongoRepository<DataRow, String>
}
In the previous example, we create a endpoint /api/datarow.
But we want to change resource path like this : /api/dataset/{id}/datarow. Is it possible with #RestRepositoryResource ?
See our model :
public class Datarow {
#Getter #Setter
private String id;
#Getter #Setter
private String datasetId;
#Getter #Setter
private Address address;
}
public class Dataset {
#Getter #Setter
private String id;
#Getter #Setter
private String name;
#Getter #Setter
private String filePath;
#Getter #Setter
private Date uploadDate;
}
See our repository :
#RepositoryRestResource(collectionResourceRel = "datarow", path = "datarow")
public interface DatarowRepository extends MongoRepository<Datarow, String> {
}
Thanks !