Couchbase - Auto generate key with user defined suffix - java

I want to save an employee object in couchbase using spring boot java. I am using reactive couchbase driver. My requirement is to save the employee object with employeeId suffixed with hard coded string "-EMPLOYEETYPE".
Example:
Object to couchbase from Java Application:
{ "employeeId" : "12345", "lname" :"ltest", "fname" : "ftest"}
While saving to couch base, key supposed to be generated like
"12345-EMPLOYEETYPE"
Below code is not working, kindly guide me how to achieve it.
Note: I am using lombok so there are no getters and setters.
#Document
public final class Employee {
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="-EMPLOYEETYPE")
private String id;
#IdAttribute
private String employeeId;
}

Found a solution. We need to create an instance variable with suffix string literal assigned to it, and annotate with #IdSuffix. (For prefix, #IdPrefix). This field will not be persisted into couchbase and only used to generate id for document.
#Document
public final class Employee {
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="-")
private String id;
#IdAttribute
private String employeeId;
#IdSuffix
private String suffix = "EMPLOYEETYPE";
}
Reference Doc: https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.autokeygeneration.configuration

Related

spring data jpa entity never found by id

I am using spring data jpa, spring boot and h2 database.
My repository looks like this
public interface IComponentStorageRepository extends JpaRepository<ComponentData, String> {
}
My domain object looks like this
#Entity
#Table(name = "component_data")
public class ComponentData {
#Column(name = "component_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String componentId;
private String description;
with overriden equals and hashcode.
I have a service method that looks like this.
#Override
public void updateComponent(String componentId, String description) {
if (repository.existsById(componentId)) {
ComponentData stored = repository.getOne(componentId);
stored.setDescription(description);
repository.saveAndFlush(stored);
} else {
ComponentData stored = new ComponentData();
stored.setComponentId(componentId);
stored.setDescription(description;
repository.saveAndFlush(newResult);
}
}
It firstly performs a check if the object exists (to prevent EntityNotFound exception) and then is trying to read one. If no object found it supposed to create a new one.
But each time I am trying to invoke the method - it is never able to find the entity. Every time it creates a new one.
I originally used repository.save and had #Transactional over the method but it didn't help either. I also haven't specified any properties and use everything default.
What is the problem
#GeneratedValue(strategy = GenerationType.IDENTITY) can't be used with String type and what i know it's not supported by the H2 inmemory DB.
When you want to use the key as String you have to assign it manually before persisting
without #GeneratedValue anotation or define the #GeneratedValue for String type properly.
There is an example from #VladMichalcea
https://vladmihalcea.com/hibernate-and-uuid-identifiers/ .
Another option would be to change the type of the primary key to be #GeneratedValue supported types
long (Long), int(Integer).

Nested reference object is persisting as null

I am trying to store below pojo in couchbase with spring-data, but persist json is storing "user field of type User" as null.
#JsonInclude(value = Include.NON_EMPTY)
#Document
public class ProjectXYZ {
#Id
#GeneratedValue(strategy = GenerationStrategy.UNIQUE)
private String id;
#Field
private String prjname;
#Field
private User user;
//setter and getter
}
Update:
User Pojo
#JsonInclude(value = Include.NON_EMPTY)
#Document
public class User {
#Id
#Field
private String id;
#Field
private String email;
#Field
private String firstName;
#Field
private String lastName;
//setter and getter
}
And as below I am saving it, All works fine and as expected but User object get stored as null.
ProjectXYZ project = new ProjectXYZ();
project.setUser(getUser(request));
project = projectXYZService.createProject(project);
References are not directly supported through Spring data couchbase as it needs to store meta information about the reference document id.
However there is support for fetching associated entities through N1QL ANSI Joins available in current Lovelace (3.1.x) versions. Here is the documentation for it.

How to hide annotated fields in Spring Boot using custom annotations?

I have created custom annotations that I add to my Java class fields.
When I create object of that class, I want my custom annotated fields to have value: null or "" or "customAnnotation"
For example:
#Entity
public class User implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "address_id")
private Long id;
#MyCustomAnnotation
private String firstname;
private String lastname;
....
And when I create the object somewhere in the project:
User user = new User();
user.setFirstname("John");
user.setLastname("Smith");
I want it to be:
String firstname = user.getFirstname() // firstname is "" or null
String lastname = user.getLastname() // lastname is "Smith"
How to create method that will find all annotated fields in all classes in the project and do the same for all of them? Where to store this method?
I am working on the Maven, Spring Boot project.
At some point in your code you will have to implement something like this:
Class<User> obj = User.class;
if (obj.isAnnotationPresent(MyCustomAnnotation.class)) {
//your business logic
}
Sensible places for something like this would be either immediately when creating users, when getting users (for whatever reason the annotation is being used) or at an interval in a timed routine.
edit: See this tutorial: https://www.mkyong.com/java/java-custom-annotations-example/

Spring Mongo DB #DBREF

I am having trouble writing code that would allow get a user and claim details in a straightforward way. This is my MongoDB structure,
db.user.find();
user:
{
"name" : "KSK",
"claim" : [objectId("52ffc4a5d85242602e000000"),objectId("52ffc4a5d85242602e000001")]
}
claim:
[
{
"_id" : "52ffc4a5d85242602e000001",
"claimName" :"XXXX"
},
{
"_id" : "52ffc4a5d85242602e000000",
"claimName" :"YYY"
}
]
My Entity class is:
#Document(collection="user")
public class User{
#Id
private String id;
private String name;
#DBRef
private List<Claim> claim;
// setter and getter
}
Claim Class:
#Document(collection="Claim")
public class Claim{
#Id
private String id;
private String claimName;
}
I have a method to get the users by name like below,
public User findByName(String name);
If I try to hit this method am getting an error that,
No converter found capable of converting from type org.bson.types.ObjectId to type java.lang.String
So I changed my User entity class as like below,
Instead of private List<Claim> claim;
Changed as Private List<ObjectId> claim;
Now if I execute a method(findByName), I get a user object that has both claimed object ids ("52ffc4a5d85242602e000001","52ffc4a5d85242602e000000"), then iterate the claim list and get the claim details corresponding to the claim object Id.
Instead of doing this, when I execute findByName method I want to get a user and claim details. How can I achieve this functionality?
If you reference your Claims in the User class with #DBRef, your JSON should not only contain the ID but the reference to the collection where to find the ID as well, like this:
{
"name" : "KSK",
"claim" : [
{
"$ref" : "claim", // the target collection
"$id" : ObjectId("52ffc4a5d85242602e000000")
}
]
}
That is how Spring-Data maps your Java objects to MongoDB. If you start with a blank database and let Spring create and save the relations, you should have no problems using
#DBRef List<Claim> claims;
My suggestion is not to set that Claim class into separate #Document or just switch back to Relational Databases, because it's not a Mongo approach.
Also, if you insist on current architecture you can try using #DBRef above that List in User.class into smth like this:
public class ParentModel {
#Id
private String id;
private String name;
private ParentType parentType;
private SubType subType;
#DBRef
private List<Model> models;
....
}
as an alternative to #DBRef, take a look at RelMongo (link)
which provides a powerfull way to manage relations, in your case it will be like this :
#OneToMany(fetch = FetchType.LAZY)
private list<Claim> claims;

Referencing in MongoDB

Sorry but I'm so newbie to MongoDB and Spring-data and i have a question about these two classes :
#Document(collection = "person")
public class Person {
/**
*
*/
private static final long serialVersionUID = 6268875544266598239L;
#Id
private String Id;
private String name;
//#DBRef(db = "mail")
ArrayList<Mail> mails = new ArrayList<Mail>();
and the other one is :
#Document(collection = "mail")
public class Mail {
/**
*
*/
private static final long serialVersionUID = 9149555841222037638L;
#Id
private String Id;
private String mail;
Person person;
Will I have a problem in referencing in this case ? I mean do i need to put #DBref or #Reference or any other annotation to work as for the #ManyToOne annotation in JPA? I saw many exemples but i cant get the point does it work without any annotation ?
Without annotation it will save mail objects inline in the person documents. Viceversa with the annotation it will save the mail DBRefs in the person documents.
Example:
person document without #DBRef in: {"id":"foo", "name":"bar", "mails":[{"id":"abc", "mail":"hello"},{"id":"def","mail":"world"}]}
person document with #DBRef: {"id":"foo", "name":"bar", "mails":[{"$ref":"mail","$id":"abc"},{"$ref":"mail","$id":"def"}]}
This means that if you need consistency between the person and the mail collections you should use #DBRef, in this case its behaviour is like a #OneToMany annotation in JPA context.
But if you need a relation between two documents in the 99% of the cases you need a relational dbms instead of mongo.

Categories

Resources