No mapping metadata found for java.lang.Object - Couchbase

≡放荡痞女 提交于 2019-11-27 08:51:26

问题


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'


回答1:


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);
        }
    }

}



回答2:


If you absolutely need the Map:

Looks like the problem is twofold:

  1. 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() {}.
  2. The Map you store contains another level of nesting, as a generic Map 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 Maps 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!