-
Notifications
You must be signed in to change notification settings - Fork 192
MappingCouchbaseConverter.read() is not recursive #1312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I made an ARepsitory and did a save followed by a find.
src/test/resources/integration.properties
I get the expected result:
From CouchbaseTemplate.support().decodeEntity()
|
the stacktrace from decodeEntity() will be this. See the two calls at read:243, MappingCouchbaseConverter? That's the recursion. The second call is initiated from read:Value:846 because the 'value' is a(nother) CouchbaseDocument.
btw - The CouchbaseTemplateSupport object and its decodeEntity() method are public, so you shouldn't have to dig into MappingCouchbaseConverter.read(). #1210 |
If you post your code, I'll run it in the debugger to see what's going on. |
Here is the code : Class definition@Data
abstract public class BaseManageableEntity {
@Id
protected String id;
@Field("dag_paths")
protected List<DagPath> dagPaths = new ArrayList<>();
abstract public ManageableType getManageableType();
@Data
@AllArgsConstructor
@EqualsAndHashCode
public static class DagPath {
private LinkType pathType;
private List<DagNode> path;
@Data
@EqualsAndHashCode
public static class DagNode {
private String id;
private ManageableType type;
private DagNode() {}
public static DagNode of(BaseManageableEntity manageable) {
if (manageable.getId() == null) throw new IllegalArgumentException();
if (manageable.getManageableType() == null) throw new IllegalArgumentException();
var node = new DagNode();
node.id = manageable.getId();
node.type = manageable.getManageableType();
return node;
}
}
}
}
@Document
@Data
@EqualsAndHashCode(callSuper = true)
public class Foo extends BaseManageableEntity {
String title;
public ManageableType getManageableType() {
return ManageableType. ManageableTypeOne;
}
}
public enum ManageableType {
ManageableTypeOne, ManageableTypeTwo
}
public enum LinkType {
LinkTypeOne, LinkTypeTwo
} // Utility functions
public <T> T toDomainEntity(byte[] obj, Class<T> clazz) {
JsonObject json = serializer.deserialize(JsonObject.class, obj);
Class<?> targetClass = Class.forName(json.get("_class").toString());
if (!clazz.isAssignableFrom(targetClass)) {
throw new IllegalArgumentException(String.format("Trying to assign %s to %s", targetClass, clazz));
}
CouchbaseDocument document = new CouchbaseDocument()
.setId(json.get(TemplateUtils.SELECT_ID).toString())
.setContent(json);
return (T) couchbaseTemplate.getConverter().read(targetClass, document);
}
public <T> List<T> toDomainEntities(List<byte[]> rows, Class<T> clazz) {
return rows.stream().map(obj -> toDomainEntity(obj, clazz)).collect(Collectors.toList());
} // Execution
QueryResult results = cluster.query(localQuery, QueryOptions.queryOptions().parameters(JsonObject.from(localMap)).adhoc(isAdHoc()));
return toDomainEntities(results.rowsAs(byte[].class), clazz); |
Could you provide an input data? Thanks. |
The difference could be that the fields are lists of sub-documents. But it should still work |
I have edited the code in my previous comment to be more complete. var a = new Foo();
a.setId("a");
var b = new Foo();
b.setId("b");
var dagPath = new BaseManageableEntity.DagPath(LinkType.LinkTypeOne, List.of(BaseManageableEntity.DagPath.DagNode.of(a), BaseManageableEntity.DagPath.DagNode.of(b)));
b.getDagPaths().add(dagPath); |
Foo doesn't implement getManageableType() from BaseManageableEntity. |
I've updated the code. |
couchbaseTemplate.insertById()/findById() (which uses CouchbaseTemplateSupport.decodeEntity) seems to work:
Where does 'serializer' in toDomainEntity come from? |
It comes from |
I tried to use |
The issue here (in 1312) is that in the CouchbaseDocument Foo, the List<> dagPath is an ArrayList (maybe it should be a CouchbaseList?) and it falls through to the else. I'll look into it. In the meantime, can you use either the template or repository? Or maybe we can skip the CouchbaseDocument and go from use a String as the source.
|
Replace your toEntity() with this:
|
This looks to be the same issue as #1276 |
The row needs to be decoded by the translationService. The translationService can be @Autowired from the config (this is what CouchbaseTemplateSupport.decodeEntity() does. The ArrayList is replaced by a CouchbaseList of CouchbaseDocuments, which MappingCouchbaseConverter converts to a List.
|
After moving to |
I'm going to keep this open as someone else hit this and I need to update the documentation. |
Is the documentation open to PRs ? |
Yes. They live in https://github.com/spring-projects/spring-data-couchbase/tree/main/src/main/asciidoc |
Having a sample project would help a lot to understand the architecture. |
There are samples in src/test/java/org/springframework/data/couchbase/repository/query/CouchbaseRepositoryQuerydslIntegrationTests.java
Bonus - to only create the bucket once and not delete it at the end of the tests. src/test/java/org/springframework/data/couchbase/util/UnmanagedTestCluster.java |
Using
Cluster.query()
I'm parsing the result into classes that have child object.A quick exemple to visualise :
Doing
converter.read(A.class, document)
leads tonestedObject
being aHashMap<String, String>
instead of aSubA
as anyone would expect. Am I doing this wrong or are my expectations correct ?The text was updated successfully, but these errors were encountered: