I am trying to directly populate the configuration object from the YAML file using #ConfigurationProperties. But when I checked the person's object, name and age got populated but the child is null. I am using the spring boot 2.7.4 version. Is this not supported by spring or any other way to handle such a situation?
#ConfigurationProperties("config")
#Component
public class PersonConfiguration {
private Person person;
//setter getters
}
public class Person {
private String name;
private int age;
#NestedConfigurationProperty
private Person child;
//setter getters of all 3
}
config:
person:
name: "my name"
age: 40
child:
name: "child1"
age: 14
You should not need PersonConfiguration
This will work:
#Configuration
#ConfigurationProperties("config.person")
public class Person {
private String name;
private int age;
private Person child;
//setter and getters
}
It seems like your child definition in config file doesn´t represent the Person class structure, it is missing child attribute. Try this:
config:
person:
name: "my name"
age: 40
child:
name: "child1"
age: 14
child: null
Related
I want to run different instances of my application in which the entity is different.
For example, one instance of application will have all the 3 attributes of customer table and another instance will have only 2 attributes of the customer table ( say firstName and lastName only).
Is there any way to configure it through the application.properties files / spring-boot provides any annotation that can handle this ?
input dto for postman
{
"id":1,
"firstName":"Tom",
"lastName":"Holland",
"address":{
"streetName":"London Streets",
"houseNumber":"123"
}
}
In case that property is set as off, then the table consists of id,firstName , lastName and Address.streetName,address.houseNumber .
In case that property is set as on, then the table consists of only id,firstName and lastName .
Controller Class
#RestController
public class CustomerController {
#Autowired
private CustomerService service;
#PostMapping("/customer")
public String addCustomer(#RequestBody Customer c)
{
service.addCustomer(c);
return "Customer added successfully " ;
}
}
Customer entity
#Entity
#Data
public class Customer {
#Id
private Long id;
private String firstName;
private String lastName;
// any spring property to configure this from app.properties
#Embedded
private Address address;
}
Address table
#Data
public class Address {
private String streetName;
private String houseNumber;
}
service layer
#Service
public class CustomerService {
#Autowired
private CustomerRepository customerRepo;
public void addCustomer(Customer customer)
{
customerRepo.save(customer);
}
}
app.properties
spring.datasource.url = jdbc:postgresql://localhost:5432/customerDirectory
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=create-drop
I know in spring boot that creating a find method in the repository will be base on the variable name of the entity. How can I create a find method in the repository if the variable in my entity is in a camel case. This is what I created is this right?
class Person {
private int id;
private Teacher teacher; //other variable...getters and setters }
private BranchManager branchManager; //other variable...getters and setters }
class Teacher {
private String firstName ;
private String lastName; //getters and setters }
class BranchManager {
private String firstName ;
private String lastName; //getters and setters }
in my repository
#Repository
public interface PersonRepository extends CrudRepository<Person, Long>{
public Person findPersonByTeacherFirstName(String firstName);
//how to find Person by BranchManager firstName and lastName
}
First of all, you have not declared Teacher object in Person. Assuming that you will declare as follows
private Teacher teacher; // name of this object is important to create the repository methods
Try
List<Person> findByTeacher_FirstName(String name);
Note that it findBy returns a List.
If you want to return only the first record. You can use the following
Person findFirstByTeacher_FirstName(String name);
Also, Personally I prefer
Optional<Person> findFirstByTeacher_FirstName(String name);
as this will return Optional.empty() in case it couldn't find a record. Also, it will force you to check for its presence, thereby, avoiding NullPointerException.
Update 1
As requested in comment,
If you want to you want to find by firstName and lastName, you can use the following
Person findFirstByTeacher_FirstNameAndTeacher_LastName(String firstName, String lastName);
You can refer to this link for these conventions.
Update 2
Search by branchManager's firstName and lastName
Person findFirstByBranchManager_FirstNameAndBranchManager_LastName(String firstName, String lastName);
Update 3
As mentioned by Aluan Haddad in comments, this practice is not scalable.
As an option, I am giving an alternative way to hit queries to DB.
You can create an example object and pass it to findAll(Example e) implementation of JpaRepository.
final Teacher exampleTeacher = new Teacher();
exampleTeacher.setName("Teacher Name");
final Person examplePerson = new Person();
example.setTeacher(exampleTeacher);
Now pass this examplePerson to Repository using
List<Person> findAll(Example.of(examplePerson));
This will return all the persons whose teacher's name is Teacher Name.
And as an alternative to C# EntityFramework, you can use QueryDSL in Java.
I am playing around with Spring Data Rest. One thing I am not being able to accomplish is to store nested objects in dedicated repositories. Here are my two model classes Person and Address:
#Entity
public class Address {
#NotEmpty public String address, email;
#Id public String id;
}
#Entity
public class Person {
#Id public String id;
public String firstName, lastName;
#OneToOne public Address address;
}
And here my two Mongo repositories that I use within Spring Boot app.
#RepositoryRestResource(collectionResourceRel = "person", path = "person")
public interface PersonRepository extends MongoRepository<Person, String> {}
#RepositoryRestResource(collectionResourceRel = "address", path = "address")
public interface AddressRepository extends MongoRepository<Address, String> {}
Now, I make the following post request to create a person.
{
"firstName": "My first name",
"lastName": "My last name",
"id":"50e30c24-b8b7-4110-a421-687f67c077d4",
"address": {
"id":"8969abf3-17c5-4d7f-bc8c-16dd97808510",
"address": "fgfgfg",
"email": "fgfggf"
}
}
The person is created in the Person repository. And when I pull the person from the repository, it very well contains the address. However, the address is not stored in the address repository. Instead it is stored inline with the person.
Though if I understand the documentation correctly (see http://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts.projections) , in this case, because the Person repository is defined, the Person resource should render the address as a URI to it's corresponding resource, which I presume would be stored in a separate repository.
So, the question is how do I cause the address to be stored in a separate repository? Could it be that this doesn't work with MongoRepository as described?
If you are working with MongoDB specifically, don't use JPA annotations.
The two magical annotations you do want are these:
#org.springframework.data.annotation.Id
#org.springframework.data.mongodb.core.mapping.DBRef
I fully qualified them above so you could see the difference between other similar annotations.
#DBRef is what tells Springs MongoDB drivers to store those objects in a separate bucket.
Here are your new classes:
public class Address {
#NotEmpty public String address, email;
#Id public String id;
}
public class Person {
#Id public String id;
public String firstName, lastName;
#DBRef public Address address;
}
I have a composite object that I wish to store in mongodb (using spring annotations). The object is as follows:
#Document(collection="person")
class Person {
#Id
private String id;
private Address address;
private String name;
}
and the composite class Address:
#Document
class Address {
#Indexed
private Long countryId;
private String street;
#Indexed
private String city
}
I need both country and city to be indexed as part of the person collection. Alas, no index is created for them. Any ideas how to create the index?
I have tried the following which works but is not elegant:
#Document(collection="person")
#CompoundIndexes({
#CompoundIndex(name = "countryId", def = "{'address.countryId': 1}")
})
class Person {
You can set up multiple secondary indexes, if you wish. This would be a good place to start.
How to load two attributes of reference document/entity using morphia
I have a Class Person and School like this
person class
#Entity
public class Person {
#Id private ObjectId id;
private String name;
#Embedded private PersonEducation schoolInfo;
}
#Embedded
public class PersonEduction {
#Reference private School school;
private String year;
private String degree;
}
School Class
#Entity
public class School {
#Id private ObjectId id;
private String name;
private String address;
private String description;
}
How I can get id and and name fields of School in Person class
example
When i want to person
Person person = datastore.find(Person.class).field("name").equals("xyz").get();
person.gerSchoolInfo();
Response (Not want all School class fields)
{school:{_id:ObjectId("4fcef3e20364a375e7631fb0"), name:"SchoolA"}, year:"1990", degree:"MBA" }
and If I query school where _id=ObjectId("4fcef3e20364a375e7631fb0"), I get all School fields
{_id:ObjectId("4fcef3e20364a375e7631fb0"), name:"xyz", address="some add", description="some desc"}
Instead of using #Reference you should use
key<School> school;
and use custom query to load it.
datastore.createQuery(School.class).retrivedFields(true, "id","name");
To give an alternative to mtariq, replace
#Reference private School school;
with
private ObjectId schoolId;
and fetch it yourself. However since your School class is so simple I think you'd be better off using Lazy loading, so:
#Reference #Lazy private School school;
This will only load the school object when/if it is referenced.