Spring Data Couchbase - CrudRepository - java

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?

Related

Deserializing complex JSON response using Jackson

I am developing my web application backend using Spring. In particular, my application manages data on soccer teams and their players.
My application interacts with a third party REST API to fetch team and player data.
As for the teams, I created a Team entity as follows:
#Data
#Table(name = "team")
#Entity
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
private String name;
private String logoUrl;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "team")
private Set<Player> players;
}
The response that comes to me from the API, however, has a particular structure and contains an array of Teams in the "response" node.
Here is the structure of the response:
{
"get":"teams",
"parameters":{
"league":"135",
"season":"2020"
},
"errors":[
],
"results":20,
"paging":{
"current":1,
"total":1
},
"response":[
{
"team":{
"id":487,
"name":"Lazio",
"country":"Italy",
"founded":1900,
"national":false,
"logo":"https:\/\/media.api-sports.io\/football\/teams\/487.png"
},
"venue":{
"id":910,
"name":"Stadio Olimpico",
"address":"Viale dei Gladiatori, 2 \/ Via del Foro Italico",
"city":"Roma",
"capacity":68530,
"surface":"grass",
"image":"https:\/\/media.api-sports.io\/football\/venues\/910.png"
}
},
{
"team":{
"id":488,
"name":"Sassuolo",
"country":"Italy",
"founded":1922,
"national":false,
"logo":"https:\/\/media.api-sports.io\/football\/teams\/488.png"
},
"venue":{
"id":935,
"name":"MAPEI Stadium - Citt\u00e0 del Tricolore",
"address":"Piazza Azzuri d&apos;Italia, 1",
"city":"Reggio nell&apos;Emilia",
"capacity":23717,
"surface":"grass",
"image":"https:\/\/media.api-sports.io\/football\/venues\/935.png"
}
},
... // Other team objects
]
}
How can I parse the answer to get a List<Team> using the Jackson library?
You should create classes for Jackson that match result structure then convert instances of those classes to your Team class. Using same class for JPA entity and for Jackson deserialization is a bad idea.
There are online services that allow generating classes like this. For example this one https://json2csharp.com/json-to-pojo generated classes like this:
// import com.fasterxml.jackson.databind.ObjectMapper; // version 2.11.1
// import com.fasterxml.jackson.annotation.JsonProperty; // version 2.11.1
/* ObjectMapper om = new ObjectMapper();
Root root = om.readValue(myJsonString), Root.class); */
public class Parameters{
public String league;
public String season;
}
public class Paging{
public int current;
public int total;
}
public class Team{
public int id;
public String name;
public String country;
public int founded;
public boolean national;
public String logo;
}
public class Venue{
public int id;
public String name;
public String address;
public String city;
public int capacity;
public String surface;
public String image;
}
public class Response{
public Team team;
public Venue venue;
}
public class Root{
public String get;
public Parameters parameters;
public List<Object> errors;
public int results;
public Paging paging;
public List<Response> response;
}
As #Sankozi said you can modelize your java pojos for json deserialization.
Then use an ObjectMapper for deserialization like :
ObjectMapper mapper = new ObjectMapper();
CollectionType javaType = mapper.getTypeFactory()
.constructCollectionType(List.class, Response.class);
List<Response> asList = mapper.readValue(jsonArray, javaType);
List<Team> teams = asList.stream()
.flatMap(response -> response.getTeam())
.collect(Collectors.toList());

How to update MongoDB #DbRef embedded collection?

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.

Spring MongoDB Some fields are not being saved nor updated at all

I'm trying to save a document in MongoDB collection via MongoRepository.save method. Here's my code.
The document class:
#Document(collection = "appointments")
public class AppointmentDocument extends AbstractCommonDocument {
#Id
private ObjectId _id;
#DBRef(lazy = true)
private ServiceDocument service;
#DBRef(lazy = true)
private FeedbackDocument feedback;
private String status;
private String appointmentType;
private String description;
private EmbeddedPeriod period;
private EmbeddedPeriod requestedPeriod;
#Deprecated
private ProviderFeedback providerFeedback;
private List<Participant> participants;
private List<AppointmentResponse> appointmentResponses;
#Deprecated
private AppointmentPayment paymentDetails;
private CommunityPayment prePayment;
private CommunityPayment postPayment;
private boolean requestedByPatient;
#Deprecated
private DateTime acceptedAt;
private DateTime requestedAt;
private DateTime confirmedAt;
private DateTime cancelledAt;
private DateTime completedAt;
private String requestMessage;
private String mondayId;
...getters & setters
}
The repository:
#Repository
public interface AppointmentRepository extends MongoRepository<AppointmentDocument, String> {
}
Code for saving record.
AppointmentDocument appointmentDocument = new AppointmentDocument();
// ...omitted set calls for other fields for brevity
appointmentDocument.setRequestedByPatient(!isProvider);
appointmentDocument.setRequestedAt(requestedAt);
appointmentDocument.setRequestMessage(request.getComment());
appointmentDocument = appointmentRepository.save(appointmentDocument);
The problem is that all the fields are getting saved inside the database except requestedAt and requestMessage field. There are no error logs, I've enabled the MongoDB logs and it appears to be sending the insert query with all the fields present there.
DEBUG o.s.data.mongodb.core.MongoTemplate - 2021-04-21 19:22:58 - Inserting Document containing fields: [service, status, period, requestedPeriod, participants, appointmentResponses, prePayment, requestedByPatient, requestedAt, requestMessage, createdAt, lastModified, _class] in collection: appointments
Still I see that requestedAt and requestMessage is missing from the document in database.
I also tried updating the record after saving the document via mongoTemplate.updateFirst method. Still no luck. Here's the code for that.
mongoTemplate.updateFirst(
new Query(where("_id").is(appointmentDocument.get_id())),
new Update()
.set("requestedAt",requestedAt)
.set("requestMessage", request.getComment()),
AppointmentDocument.class
);
Again I see logs for updating..
DEBUG o.s.data.mongodb.core.MongoTemplate - 2021-04-21 19:22:58 - Calling update using query: { "_id" : { "$oid" : "60807b92adbe1d0001c2bed6" } } and update: { "$set" : { "requestedAt" : { "$date" : 1619032978091 }, "requestMessage" : "Dummy Request message" } } in collection: appointments
Still no luck. I got no clue why this is happening. Please help.

Mapping flat DB documents to nested classes in Morphia

I am porting a Java application that used to use Jongo to communicate with MongoDB to Morphia + new MongoDB Java Driver.
In the database there are flat documents like:
{
"_id" : ObjectId("56c2e5b9b9b6e9753d4f11de"),
"field1" : "foo",
"field2" : "bar",
"field3" : NumberLong("1455613369030"),
"field4" : NumberLong("1455613369030"),
"field5" : NumberLong(58),
"field6" : NumberLong(1)
}
And there are not flat entity classes to store those documents in Java app, annotated using jackson to be usable with Jongo:
public class MyPOJOClass {
public static final String COLLECTION_NAME = "foobar";
#JsonProperty(value = "_id")
private String id;
#JsonUnwrapped
private FooBar foobar;
#JsonUnwrapped
private MyLongs longs;
// Constructor and other methods
public static class FooBar {
#JsonProperty(value = "field1")
private String foo;
#JsonProperty(value = "field2")
private String bar;
// Consteructor and other methods…
}
public static class MyLongs {
#JsonProperty(value = "field3")
private long first;
#JsonProperty(value = "field4")
private long second;
// etc…
}
}
Can I somehow port this exact structure to Morphia as is, without flattening the entity classes or expanding documents (so that foo and bar fields are in one embedded document and LongNumber fields in another document)?
I have not found any examples of the #Embedded annotation (the only one that looks relevant and gives some hope) to do such a thing. I want to end up with something like:
#Entity(MyPOJOClass.COLLECTION_NAME)
public class MyPOJOClass {
public static final String COLLECTION_NAME = "foobar";
#Id
private ObjectId id;
#Embedded(_SOME_MAGIC_?)
private FooBar foobar;
#Embedded(_SOME_MAGIC_?)
private MyLongs longs;
// Constructor and other methods
#Embedded(_SOME_MAGIC_?)
public static class FooBar {
#Property("field1")
private String foo;
#Property("field2")
private String bar;
// Consteructor and other methods…
}
#Embedded(_SOME_MAGIC_?)
public static class MyLongs {
#Property("field3")
private long first;
#Property("field4")
private long second;
// etc…
}
}

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