I'm persisting an entity in a CouchBase repository and trying to query it. The entity looks like this:
@Document(expiry = 0)
public class GsJsonStore implements Serializable {
private static final long serialVersionUID = 7133072282172062535L;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@Field
private Map<String,Object> _object;
@Field
private String _subject;
@Field
private String _predicate;
//Getters and Setters
}
I'm querying the entity by using N1QL queries on the CouchbaseOperations template like this:
String query1 = "SELECT META(default).id as _ID, META(default).cas as _CAS, default.* FROM default WHERE "+key+"="+"'"+value+"'";
List<GsJsonStore> list = operations.findByN1QL(N1qlQuery.simple(query1), GsJsonStore.class);
I'm querying for a K-V pair within the _object Map. I get an error : No mapping metadata found for java.lang.Object
Why is this happening? Also, I'm storing a json object as Map<String,Object>
in Couchbase, I tried using the jackson JsonNode
type but the object was also storing class related metadata. Is there a better datatype to represent the json type?
EDIT
Data stored in Couchbase :
{
"_object" : {
"Name" : "Kapil",
"Age" : {
"Nested" : 21
}
},
"_subject" : "Subject",
"_predicate" : "Predicate"
}
The key I'm looking for is _object.Name and value is 'Kapil'
As explained here you should override the default SPMappingCouchbaseConverter.
Here is how I solved the problem:
@Bean
public MappingCouchbaseConverter mappingCouchbaseConverter() throws Exception {
return new MyMappingCouchbaseConverter(couchbaseMappingContext());
}
private class MyMappingCouchbaseConverter extends MappingCouchbaseConverter {
MyMappingCouchbaseConverter(MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext) {
super(mappingContext);
}
@Override
@SuppressWarnings("unchecked")
protected <R> R read(final TypeInformation<R> type, final CouchbaseDocument source, final Object parent) {
if (Object.class == typeMapper.readType(source, type).getType()) {
return (R) source.export();
} else {
return super.read(type, source, parent);
}
}
}
If you absolutely need the Map
:
Looks like the problem is twofold:
- re-instantiation by reflection using a constructor with parameters doesn't seem to work that well from my tests, so I'd add a private empty constructor
private GsJsonStore() {}
. - The
Map
you store contains another level of nesting, as a genericMap
as well. This is problematic for the framework to deal with at deserialization time.
You could try to either flatten "Age" into the top-level _object
map or create a dedicated class for the "Age" entry (simply with a Nested
field of type int) and store that instead. Note that in the later case, the framework should add _class
metadata to the "Age" JSON that is stored, which explains how in this case it manages to deserialize it later on.
If you can modelize more specifically than a Map
:
The best way would still be to create a proper GsEntity
class without generic collections/maps but named attributes (and possibly meaningful entity classes for sub values as well).
This would mitigate the problems with Map
s and allow for automatic creation of the query by simply adding a method signature in the repository interface. Something like that:
public class ContentObject {
private String name;
private int age;
public ContentObject(String name, int age) {
this.name = name;
this.age = age;
}
}
@Document(expiry = 0)
public class GsEntity implements Serializable {
private static final long serialVersionUID = 7133072282172062535L;
@Id
private String id;
@Field
private ContentObject object;
@Field
private String subject;
@Field
private String predicate;
//EMPTY CONSTRUCTOR
//Getters and Setters
}
public interface GsEntityRepository extends CouchbaseRepository<GsEntity, String> {
@Query
List<GsEntity> findByObjectNameEquals(String nameValue);
}
Note that the attributes have been renamed to remove the underscore, as it doesn't follow Java naming conventions and it would prevent the interface's method to be properly mapped to the attribute.
The method is analyzed roughly like this: findBy
Object
Name
Equals
.
This translate to a SELECT of GsEntity
objects which object
field has a name
field which has the same value as the string passed as a parameter.
来源:https://stackoverflow.com/questions/36002986/no-mapping-metadata-found-for-java-lang-object-couchbase