How to set Nested Object with Mongotemplate Spring - java

I'm still new in mongodb, If I have a class like below and I want to set a property Role which is Object Type Property, how can I achieve it ? please check the class below
#Document(collection="User")
public class UserBean {
#Id
private String id;
private String userName;
private String password;
private RoleBean role;
}
#Document(collection="Role")
public class RoleBean {
#Id
private String id;
private String roleID;
private String roleName;
}
I need to set the UserBean's role property. So what is the best way to achieve it? Thanks.

Spring Mongo Template not saving the list of custom objects to MongoDb please see if this quation is already answered, or answer satisfies your requirements.

Related

How to create different JSON output for a complex object

I would like to generate different Json output for the same complex Java object depending on the use case.
For example check the following code:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
private Department department;
...
}
class Department {
private Long id;
private String name;
private String address;
...
}
class EmployeeDetail {
private Long id;
private int salary;
private Date birthDate;
...
}
If I convert Employee to Json all of the fields from Employee, EmployeeDetail and Department will be present. And it is good for one use case.
However in the second use case I would like to skip Department details except the id field but keep the complete EmployeeDetail.
I know that I can add something similar #JsonView(EmployeeView.Basic.class) to the id field in the Department class and use Json views. However for cleaner code I would like to solve it inside the Employee class something like this:
class Employee {
private Long id;
private String name;
#JsonAllFields
private EmployeeDetail detail;
#JsonIdOnly
private Department department;
...
}
At the moment I use the Jackson library but can switch if required.
i think you can use com.fasterxml.jackson.annotation.
#JsonIgnore is used to ignore the logical property used in serialization and deserialization. #JsonIgnore can be used at setter, getter or field. You can use it in the fields in Department class except on ID. There are so many ways to do it. Either you can allow the only getter in serialization etc.
Example:
#JsonIgnore(false)
private String id;
OR
#JsonIgnoreProperties({ "bookName", "bookCategory" })
public class Book {
#JsonProperty("bookId")
private String id;
#JsonProperty("bookName")
private String name;
#JsonProperty("bookCategory")
private String category;
}
To know more about it, please refer: https://www.concretepage.com/jackson-api/jackson-jsonignore-jsonignoreproperties-and-jsonignoretype
I hope this helps.
Just found a solution using #JsonFilter
Now the Employee class looks like this:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
#JsonFilter("departmentFilter")
private Department department;
...
}
And the code to generate the limited json looks like this:
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id"));
mapper.setFilterProvider(filterProvider);
One small cons is that now I also need to define the filter to generate the full, detailed json like this:
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.serializeAll());

Web application spring boot and angular 5

I am making a simple CRUD application using Spring boot and MongoDB, the problem that I am facing is that I don't know how to define the model classes.
My application should be like this:
A site has some characteristics such as an ID, region, city, ... and contains 4 parts (cellulars) that each has its own characteristics. Any help would be appreciated.
This is what I have so far:
public class Site {
#Id
String siteId;
String projectPhase;
String region;
String city;
String siteName;
String newSiteName;
String clusterName ;
String longitude ;
String lattitude ;
#OneToMany(mappedBy = "siteId")
List L;
What I want to know is how do I associate another class inside this one.
Annotations like #OneToMany are typically used within JPA-context, and are unnecessary when using Spring Data MongoDB. This is also mentioned by the documentation:
There’s no need to use something like #OneToMany because the mapping framework sees that you want a one-to-many relationship because there is a List of objects.
You have a few options when you want to define one-to-many relations when using MongoDB. The first of them is to define them as embedded objects within the same document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
private List<Part> cellulars;
}
public class Part {
private String characteristic1;
private String characteristic2;
}
This means that the parts do not exist on their own, so they don't need their own ID either.
Another possibility is to reference to another document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
#DBRef
private List<Part> cellulars;
}
#Document
public class Part {
#Id
private String id;
private String characteristic1;
private String characteristic2;
}
In this case, parts are also separate documents, and a site simply contains a reference to the part.

LdapRepository update spring-ldap

Spring LdapRepository save() method throws exception when I'm trying to update an existing object in LDAP database.
org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException: ERR_250_ENTRY_ALREADY_EXISTS
What method should I use to update existing ldap objects?
Person class:
#Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })
public class Person implements Serializable {
public Person() {
}
#Id
private Name dn;
#Attribute(name = "cn")
#DnAttribute(value = "cn")
#JsonProperty("cn")
private String fullName;
#Attribute(name = "uid")
private String uid;
private String mail;
#Attribute(name = "sn")
private String surname;
//setters and getters
}
Person repo interface:
public interface PersonRepo extends LdapRepository<Person> {
}
That's how I'm updating person:
personRepo.save(person);
Default implementation for Spring LDAP repositories is SimpleLdapRepository, that checks the property annotated with #Id to determine if the objects is new - and perform create, or old - and perform update.
I'm guessing that Person.dn is null when you're trying to perform update.
You also can take the control over this by implementing org.springframework.data.domain.Persistable and place your logic in the isNew() method.
See the implementation details.

Indexing composite object in spring mongodb

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.

Only using #JsonIgnore during serialization, but not deserialization

I have a user object that is sent to and from the server. When I send out the user object, I don't want to send the hashed password to the client. So, I added #JsonIgnore on the password property, but this also blocks it from being deserialized into the password that makes it hard to sign up users when they don't have a password.
How can I only get #JsonIgnore to apply to serialization and not deserialization? I'm using Spring JSONView, so I don't have a ton of control over the ObjectMapper.
Things I've tried:
Add #JsonIgnore to the property
Add #JsonIgnore on the getter method only
Exactly how to do this depends on the version of Jackson that you're using. This changed around version 1.9, before that, you could do this by adding #JsonIgnore to the getter.
Which you've tried:
Add #JsonIgnore on the getter method only
Do this, and also add a specific #JsonProperty annotation for your JSON "password" field name to the setter method for the password on your object.
More recent versions of Jackson have added READ_ONLY and WRITE_ONLY annotation arguments for JsonProperty. So you could also do something like:
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
Docs can be found here.
In order to accomplish this, all that we need is two annotations:
#JsonIgnore
#JsonProperty
Use #JsonIgnore on the class member and its getter, and #JsonProperty on its setter. A sample illustration would help to do this:
class User {
// More fields here
#JsonIgnore
private String password;
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(final String password) {
this.password = password;
}
}
Since version 2.6: a more intuitive way is to use the com.fasterxml.jackson.annotation.JsonProperty annotation on the field:
#JsonProperty(access = Access.WRITE_ONLY)
private String myField;
Even if a getter exists, the field value is excluded from serialization.
JavaDoc says:
/**
* Access setting that means that the property may only be written (set)
* for deserialization,
* but will not be read (get) on serialization, that is, the value of the property
* is not included in serialization.
*/
WRITE_ONLY
In case you need it the other way around, just use Access.READ_ONLY.
In my case, I have Jackson automatically (de)serializing objects that I return from a Spring MVC controller (I am using #RestController with Spring 4.1.6). I had to use com.fasterxml.jackson.annotation.JsonIgnore instead of org.codehaus.jackson.annotate.JsonIgnore, as otherwise, it simply did nothing.
Another easy way to handle this is to use the argument allowSetters=truein the annotation. This will allow the password to be deserialized into your dto but it will not serialize it into a response body that uses contains object.
example:
#JsonIgnoreProperties(allowSetters = true, value = {"bar"})
class Pojo{
String foo;
String bar;
}
Both foo and bar are populated in the object, but only foo is written into a response body.
"user": {
"firstName": "Musa",
"lastName": "Aliyev",
"email": "klaudi2012#gmail.com",
"passwordIn": "98989898", (or encoded version in front if we not using https)
"country": "Azeribaijan",
"phone": "+994707702747"
}
#CrossOrigin(methods=RequestMethod.POST)
#RequestMapping("/public/register")
public #ResponseBody MsgKit registerNewUsert(#RequestBody User u){
root.registerUser(u);
return new MsgKit("registered");
}
#Service
#Transactional
public class RootBsn {
#Autowired UserRepository userRepo;
public void registerUser(User u) throws Exception{
u.setPassword(u.getPasswordIn());
//Generate some salt and setPassword (encoded - salt+password)
User u=userRepo.save(u);
System.out.println("Registration information saved");
}
}
#Entity
#JsonIgnoreProperties({"recordDate","modificationDate","status","createdBy","modifiedBy","salt","password"})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String country;
#Column(name="CREATED_BY")
private String createdBy;
private String email;
#Column(name="FIRST_NAME")
private String firstName;
#Column(name="LAST_LOGIN_DATE")
private Timestamp lastLoginDate;
#Column(name="LAST_NAME")
private String lastName;
#Column(name="MODIFICATION_DATE")
private Timestamp modificationDate;
#Column(name="MODIFIED_BY")
private String modifiedBy;
private String password;
#Transient
private String passwordIn;
private String phone;
#Column(name="RECORD_DATE")
private Timestamp recordDate;
private String salt;
private String status;
#Column(name="USER_STATUS")
private String userStatus;
public User() {
}
// getters and setters
}
You can use #JsonIgnoreProperties at class level and put variables you want to igonre in json in "value" parameter.Worked for me fine.
#JsonIgnoreProperties(value = { "myVariable1","myVariable2" })
public class MyClass {
private int myVariable1;,
private int myVariable2;
}
You can also do like:
#JsonIgnore
#JsonProperty(access = Access.WRITE_ONLY)
private String password;
It's worked for me
I was looking for something similar. I still wanted my property serialized but wanted to alter the value using a different getter. In the below example, I'm deserializing the real password but serializing to a masked password. Here's how to do it:
public class User() {
private static final String PASSWORD_MASK = "*********";
#JsonIgnore
private String password;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public String setPassword(String password) {
if (!password.equals(PASSWORD_MASK) {
this.password = password;
}
}
public String getPassword() {
return password;
}
#JsonProperty("password")
public String getPasswordMasked() {
return PASSWORD_MASK;
}
}
The ideal solution would be to use DTO (data transfer object)

Categories