Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic type to repository for couchbase using spring boot

I'm creating an utility in Spring Boot to connect and insert/upsert data into the couchbase in the more generic way possible.

I have something like this:

public interface GenericRepository extends CouchbaseRepository<MyClass, String> {
}

Where I have MyClass I would like to accept any kind of document to insert into couchbase.

I have tried some things like using the generic type T but without success because I got the following error:

Caused by: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class java.lang.Object!

My structure is: service (interface/impl) > DAO (interface/impl) > repository

Extra info: Across the above model I am passing a Generic type T. I am calling the service with my Pojo with the @Document annotation.

The goal is to remove the "dependency" of having one repository class for each type of Document.

like image 499
Fabio Cardoso Avatar asked Oct 10 '19 09:10

Fabio Cardoso


2 Answers

You can have generic repositories (bit hacky) but with some limitation. Assume you have documents;

@Document
public class MyClass1 extends BaseClass {

    private String text1;

    public MyClass1() {
        super();
        setType(Type.MyClass1);
    }

    // getter/setters
}

@Document
public class MyClass2 extends BaseClass {

    private String text2;

    public MyClass2() {
        super();
        setType(Type.MyClass2);
    }

    // getter/setters
}

with BaseClass;

@Document
public class BaseClass { 

    private Type type;

    // other common fields if any, and getter/setters

    public enum Type {
        MyClass1, MyClass2
    }
}

Then you can have the following repository;

public interface GenericRepository<T extends BaseClass> extends CouchbaseRepository<T, String> {

    public List<T> findByType(BaseData.Type type);

    public default List<T> findAll(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        return findByType(clazz.newInstance().getType());
    }
}

and use it like;

@Autowired
private GenericRepository<MyClass1> mc1Repository;
@Autowired
private GenericRepository<MyClass2> mc2Repository;

public void doStuff() {
    MyClass1 myClass1 = new MyClass1();
    myClass1.setText1("text1");
    mc1Repository.save(myClass1);
    mc1Repository.findAll(MyClass1.class).forEach(d -> System.out.println(d.getText1()));

    MyClass2 myClass2 = new MyClass2();
    myClass2.setText2("text2");
    mc2Repository.save(myClass2);
    mc2Repository.findAll(MyClass2.class).forEach(d -> System.out.println(d.getText2()));
}

will print out;

text1
text2

But be aware that the documents will be all in same collection that is the collection for the BaseClass

Also this won't work with more than one extension (like MyClass1 extends Mid1, and Mid1 extends Base)

like image 183
buræquete Avatar answered Sep 28 '22 19:09

buræquete


UPDATE: You can build a class that does generic manipulation of an entity (save/delete/update) via the CouchbaseOperations class. All you need to do is to inject it in your service or custom repository.

I don't think this is possible via the Spring SDK (Couchbase just implements the Spring's spec). However, you can create a single generic repository using reflection and the standard Java SDK:

    Cluster cluster = CouchbaseCluster.create("localhost");
    cluster.authenticate("username", "password");
    Bucket bucket = cluster.openBucket("bucketname");

    // Create a JSON Document
    JsonObject arthur = JsonObject.create()
        .put("name", "Arthur")
        .put("email", "[email protected]")
        .put("interests", JsonArray.from("Holy Grail", "African Swallows"));

    // Store the Document
    bucket.upsert(JsonDocument.create("u:king_arthur", arthur));
like image 29
deniswsrosa Avatar answered Sep 28 '22 19:09

deniswsrosa