How to update MongoDB #DbRef embedded collection? - java

So, I am trying my hands-on MongoDB CRUD operations using spring-data-mongodb. Below are my model classes,
#Document(collection = "alumni_students")
public class AlumniStudent {
#Id
private String id;
private String firstName;
private String lastName;
private String email;
#DBRef
private AlumniDepartment alumniDepartment;
#DBRef
private List<AlumniSubject> alumniSubjects;
... getters/setters
#Document(collection = "alumni_department")
public class AlumniDepartment {
#Id
private String id;
private String departmentName;
private String location;
... getters/setters
#Document(collection = "alumni_subjects")
public class AlumniSubject {
#Id
private String id;
private String subjectName;
private int marks;
... getters/setters
I am using MongoRepository for individual collections for their operations like below,
#Repository
public interface AlumniStudentRepository extends MongoRepository<AlumniStudent, String> { }
#Repository
public interface AlumniDepartmentRepository extends MongoRepository<AlumniDepartment, String> {}
#Repository
public interface AlumniSubjectRepository extends MongoRepository<AlumniSubject, String> {}
I have so far done good while creation and getting the student details. The issue I am facing is while updating the student data. In that also specifically while updating the data, I am confused as hell.
Below is my update code from service layer,
#Autowired
AlumniStudentRepository alumniStudentRepo;
#Autowired
AlumniDepartmentRepository alumniDeptRepo;
#Autowired
AlumniSubjectRepository alumniSubjRepo;
public AlumniStudent updateStudent(AlumniStudent student, String id) {
Optional<AlumniStudent> fetchedStudent = alumniStudentRepo.findById(id);
**// UPDATE STUDENT DATA, WORKS FINE**
if (fetchedStudent.isPresent()) {
AlumniStudent studentFromDB = fetchedStudent.get();
studentFromDB.setFirstName(student.getFirstName());
studentFromDB.setLastName(student.getLastName());
studentFromDB.setEmail(student.getEmail());
**// UPDATE DEPARTMENT DATA, WORKS FINE**
if (student.getAlumniDepartment() != null) {
Optional<AlumniDepartment> deptData = alumniDeptRepo.findById(studentFromDB.getAlumniDepartment().getId());
if (deptData.isPresent()) {
AlumniDepartment alumniDepartment = deptData.get();
alumniDepartment.setDepartmentName(student.getAlumniDepartment().getDepartmentName());
alumniDepartment.setLocation(student.getAlumniDepartment().getLocation());
alumniDeptRepo.save(alumniDepartment);
studentFromDB.setAlumniDepartment(alumniDepartment);
}
}
**// UPDATE SUBJECTS ARRAY DATA.... HOW TO DO THIS?**
if (student.getAlumniSubjects() != null && !student.getAlumniSubjects().isEmpty()) {
// Problematic area. How to perform update of arraylist here?
}
return alumniStudentRepo.save(studentFromDB);
}
}
This is the URL to hit in postman :
localhost:8080/alumnistudents/60aa384ffbf1851f56c71bef
And this is the request body:
{
"firstName": "Babita",
"lastName": "Raman",
"email": "babita#gmail.com",
"alumniDepartment": {
"departmentName": "Android Developer",
"location": "Dubai"
},
"alumniSubjects": [
{
"subjectName": "Java",
"marks": 80
},
{
"subjectName": "Unit testing",
"marks": 60
},
{
"subjectName": "Docker",
"marks": 80
}
]
}
I tried some random code but ended up with
Cannot create a reference to an object with a NULL id.
Can someone help here with how to update the arrays data which is referenced as #DbRef ?
Thanks in advance everyone.

Related

Spring REST APi returns empty result on search using PagingAndSortingRepository

I am trying to build a REST API that returns a list of all transactions made by a user with a specific senderId, yet I have some issues retrieving the list itself.
A version of this works fine for my Customer functionality with age as a stand-in for senderId, so I don't understand why this is causing issues.
Whenever I search using PagingAndSortingRepository my page returns an empty JSON, like so:
{
"_embedded" : {
"transactions" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/transactions/search/findTransactionsBySenderId?senderid=1"
}
}
}
I have a Transaction class:
#Entity
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonIgnore
private Long transactionId;
private Long senderId;
private Account.AccountType senderAccountType;
private Long recipientId;
private double amountTransferred = 0;
private Date transactionDate;
public Transaction() {
}
// Getters & Setters
I have a TransactionRepository:
public interface TransactionRepository extends PagingAndSortingRepository<Transaction, Long> {
Iterable<Transaction> findTransactionsBySenderId(#Param("senderId") Long senderId);
}
And a TransactionController:
#RestController
public class TransactionController {
// TransactionController
#Autowired
TransactionRepository transactionRepository;
#GetMapping(path = "/transactions")
public Iterable<Transaction> getTransactions() {
return transactionRepository.findAll();
}
#PostMapping(path = "/transactions", consumes = {"application/json"})
public Transaction createTransaction(#RequestBody Transaction transaction) {
transactionRepository.save(transaction);
return transaction;
}
}
And my DB looks like this:

How can I Return a JSON Object without Nested Objects From Other Classes?

I want to return a JSON Object with information from two different Classes.
Like I want the username from the class User and the rolename from the Class Role together in one JSON Object.
My current code:
#Entity
#DynamicUpdate
public class User {
private String username;
private String phone;
private String email;
private Set<Role> role;
}
#Entity
public class Role {
private int idRole;
private String name;
}
#Projection(name = "CustomUser", types = {User.class})
public interface CustomUser {
String getUsername();
RoleTest getRole();
interface RoleTest {
String getName();
}
}
#Repository
public interface UserRepository extends JpaRepository<User, Integer> {
List<CustomUser> findAllBy();
}
#Controller
#RequestMapping
public class UserController {
#Autowired
private UserRepository userRepository;
#GetMapping
#ResponseStatus(HttpStatus.ACCEPTED)
public #ResponseBody List<CustomUser> getAllUsers() {
return userRepository.findAllBy();
}
}
What I currently get:
{
"role": {
"name": "ADMIN"
},
"username": "test"
}
However, my goal is it to get something like this:
{
"role": "ADMIN",
"username": "test"
}
If you are using the Jackson library, please check #JsonUnwrapped. The documentation is here
The problem here is that #JsonUnwrapped doesn't work with the Collections. As you indicated in one of your comments if the Role need not be a set, this will solve your problem.
If you have questions on why the #JsonUnwrapped doesn't work with the Collcetions, this will help to understand further.
I think you could simply do the following.
#Projection(name = "CustomUser", types = {User.class})
public interface CustomUser {
String getUsername();
#Value("#{target.getRoles(0).getName()}")
String getRole();
}
You're getting the role -> name structure because RoleTest is an interface and it might have multiple values.

Unable to deserialize JSON response into Java Objects

I know there are lots of queries on this topic but nothing has been helpful for me to resolve below issue
{
"_embedded": {
"customers": [
{
"id": 101,
"name": "John",
"city": "Ohio"
},
{
"id": 102,
"name": "Tom",
"city": "London"
}
]
}
}
for this I have created below Java objects:
#Data
public class Wrapper {
#JsonProperty("_embedded")
private Customers customer;
}
#Data
public class Customers {
#JsonProperty("customer")
private List<Foo> obj;
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Foo{
private int id;
private String name;
private String city;
}
Any help will be greatly appreciated.
You have some naming issues in your original question, but disregarding that, you could structure your classes according to the JSON to make it easier for both yourself and Gson.
Something like this would work:
public class JsonWrapper {
public Embedded _embedded;
}
public class Embedded {
public Customers customers;
}
public class Customers extends ArrayList<Foo>{ }
public class Foo{
public int id;
public String name;
public String city;
}
String json = "{\"_embedded\":{\"customers\":[{\"id\":101,\"name\":\"John\",\"city\":\"Ohio\"},{\"id\":102,\"name\":\"Tom\",\"city\":\"London\"}]}}";
JsonWrapper wrapper = new Gson().fromJson(json, JsonWrapper.class);

Spring Data Couchbase - CrudRepository

I am trying to retrieve a document from couchbase using CrudRepository interface. The document is something similar to below and has name CUSTOMER::52663829988929
{ "DATA": {
"FNAME": "Greg",
"LNAME": "CLARKE" }, "KEY": "CUSTOMER::52663829988929" }
The related class is named com.mycompany.xyz.Customer. I created a repository using the below code :
public interface CustomerRepository extends CrudRepository<Customer, String> {
}
Code for Customer Class -
public class Customer{
private static final long serialVersionUID = 1L;
#Expose #SerializedName("KEY") private String key;
#Expose #SerializedName("DATA") private Data data;
public Customer() {
}
// getters and setters
}
Code for Data class -
public class Data {
private static final long serialVersionUID = 1L;
#Expose #SerializedName("FNAME") private String fname;
#Expose #SerializedName("LNAME") private String lname;
// getters and setters
}
When I execute the below code , I am getting an empty Customer object -
customerRepository.findOne("CUSTOMER::52663829988929")
Please can you let me know what I'm missing.
EDIT:
When I looked at the documents in couchbase , it does not have _class attribute. Is this mandatory? Can't Spring Data's CRUDRepo be used to fetch documents that doesn't have _class attribute?

Struts2 + Json Serialization of items

I have the following classes:
public class Student {
private Long id ;
private String firstName;
private String lastName;
private Set<Enrollment> enroll = new HashSet<Enrollment>();
//Setters and getters
}
public class Enrollment {
private Student student;
private Course course;
Long enrollId;
//Setters and Getters
}
I have Struts2 controller and I would like to to return Serialized instance of Class Student only.
#ParentPackage("json-default")
public class JsonAction extends ActionSupport{
private Student student;
#Autowired
DbService dbService;
public String populate(){
return "populate";
}
#Action(value="/getJson", results = {
#Result(name="success", type="json")})
public String test(){
student = dbService.getSudent(new Long(1));
return "success";
}
#JSON(name="student")
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
It returns me the serializable student object with all sub classes, but I would like to have only student object without the hashset returned .
How can I tell Struts to serialize only the object?
I do have Lazy loading enabled and hashset is returned as proxy class.
See the answer here which shows the use of include and exclude properties. I don't think the example clearly shows excluding nested objects however I have used it for this purpose. If you still have issues I'll post a regex which will demonstrate this.
Problem with Json plugin in Struts 2
Edit:
Here is an example of using exclude properties in an annotation which blocks the serialization of a nested member:
#ParentPackage("json-default")
#Result(type = "json", params = {
"excludeProperties",
"^inventoryHistory\\[\\d+\\]\\.intrnmst, selectedTransactionNames, transactionNames"
})
public class InventoryHistoryAction extends ActionSupport {
...
inventoryHistory is of type InventoryHistory a JPA entity object, intrnmst references another table but because of lazy loading if it were serialized it would cause an Exception when the action is JSON serialized for this reason the exclude parameter has been added to prevent this.
Note that
\\
is required for each \ character, so a single \ would only be used in the xml where two are required because of escaping for the string to be parsed right.
#Controller
#Results({
#Result(name="json",type="json"
, params={"root","outDataMap","excludeNullProperties","true"
,"excludeProperties","^ret\\[\\d+\\]\\.city\\.province,^ret\\[\\d+\\]\\.enterprise\\.userinfos","enableGZIP","true"
})
})
public class UserinfoAction extends BaseAction {
#Action(value="login")
public String login(){
if(jsonQueryParam!=null && jsonQueryParam.length()>0)
{
user = JsonMapper.fromJson(jsonQueryParam, TUserinfo.class);
}
Assert.notNull(user);
//RESULT="ret" addOutJsonData: put List<TUserinfo> into outDataMap with key RESULT for struts2 JSONResult
addOutJsonData(RESULT, service.login(user));
return JSON;
}
public class TUserinfo implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String userid;
private String username;
private String userpwd;
private TEnterpriseinfo enterprise;
private String telphone;
private TCity city;
......
}
public class TEnterpriseinfo implements java.io.Serializable {
private String enterpriseid;
private String enterprisename;
private Set<TUserinfo> userinfos = new HashSet<TUserinfo>(0);
.......}
before set the excludeProperties property,the result is below:
{"ret":[
{
"city":{"cityename":"tianjin","cityid":"12","cityname":"天津"
,"province": {"provinceename":"tianjing","provinceid":"02","provincename":"天津"}
}
,"createddate":"2014-01-07T11:13:58"
,"enterprise":{"createddate":"2014-01-07T08:38:00","enterpriseid":"402880a5436a227501436a2277140000","enterprisename":"测试企业2","enterprisestate":0
,"userinfos":[null,{"city":{"cityename":"beijing","cityid":"11","cityname":"北京","province":{"provinceename":"beijing","provinceid":"01","provincename":"北京市"}
},"comments":"ceshi","createddate":"2004-05-07T21:23:44","enterprise":null,"lastlogindate":"2014-01-08T08:50:34","logincount":11,"telphone":"2","userid":"402880a5436a215101436a2156e10000","username":"0.5833032879881197","userpwd":"12","userstate":1,"usertype":0}]
}
,"lastlogindate":"2014-01-08T10:32:43","logincount":0,"telphone":"2","userid":"402880a5436ab13701436ab1b74a0000","username":"testUser","userpwd":"333","userstate":1,"usertype":0}]
}
after set the excludeProperties property,there are not exist province and userinfos nodes, the result is below:
{"ret":
[{
"city":{"cityename":"tianjin","cityid":"12","cityname":"天津"}
,"createddate":"2014-01-07T11:13:58"
,"enterprise":{"createddate":"2014-01-07T08:38:00","enterpriseid":"402880a5436a227501436a2277140000","enterprisename":"测试企业2","enterprisestate":0}
,"lastlogindate":"2014-01-08T11:05:32","logincount":0,"telphone":"2","userid":"402880a5436ab13701436ab1b74a0000","username":"testUser","userpwd":"333","userstate":1,"usertype":0
}]
}

Categories

Resources