2

In my PostgreSQL database I have:

CREATE TABLE category (
    // ...
    category_name_localization JSON not null,
);

In Java, I have a JDO class like so:

@javax.jdo.annotations.PersistenceCapable(table = "category" )
public class Category extends _BlueEntity implements Serializable {
    //...

    private org.json.simple.JSONObject category_name_localization;

    @javax.jdo.annotations.Column( name = "category_name_localization" )
    public org.json.simple.JSONObject getCategoryNameLocalization() {
        return category_name_localization;
    }
}

When I use this class, DataNucleus gives the following exception:

org.datanucleus.exceptions.NucleusUserException: Field "com.advantagegroup.blue.ui.entity.Category.category_name_localization" is a map that has been specified without a join table and neither the key nor the value has a mapped-by specified. This is invalid!
                at org.datanucleus.store.rdbms.RDBMSStoreManager.newJoinTable(RDBMSStoreManager.java:2720)
                at org.datanucleus.store.rdbms.mapping.java.AbstractContainerMapping.initialize(AbstractContainerMapping.java:82)
                at org.datanucleus.store.rdbms.mapping.MappingManagerImpl.getMapping(MappingManagerImpl.java:680)
                at org.datanucleus.store.rdbms.table.ClassTable.manageMembers(ClassTable.java:518)
                at org.datanucleus.store.rdbms.table.ClassTable.manageClass(ClassTable.java:424)
                at org.datanucleus.store.rdbms.table.ClassTable.initializeForClass(ClassTable.java:1250)
                at org.datanucleus.store.rdbms.table.ClassTable.initialize(ClassTable.java:271)
                at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.initializeClassTables(RDBMSStoreManager.java:3288)
                at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.run(RDBMSStoreManager.java:2897)
                at org.datanucleus.store.rdbms.AbstractSchemaTransaction.execute(AbstractSchemaTransaction.java:118)
                at org.datanucleus.store.rdbms.RDBMSStoreManager.manageClasses(RDBMSStoreManager.java:1637)
                at org.datanucleus.store.rdbms.RDBMSStoreManager.getDatastoreClass(RDBMSStoreManager.java:665)
                at org.datanucleus.store.rdbms.RDBMSStoreManager.getPropertiesForGenerator(RDBMSStoreManager.java:2098)
                at org.datanucleus.store.AbstractStoreManager.getStrategyValue(AbstractStoreManager.java:1278)
                at org.datanucleus.ExecutionContextImpl.newObjectId(ExecutionContextImpl.java:3668)
                at org.datanucleus.state.StateManagerImpl.setIdentity(StateManagerImpl.java:2276)
                at org.datanucleus.state.StateManagerImpl.initialiseForPersistentNew(StateManagerImpl.java:482)
                at org.datanucleus.state.StateManagerImpl.initialiseForPersistentNew(StateManagerImpl.java:122)
                at org.datanucleus.state.ObjectProviderFactoryImpl.newForPersistentNew(ObjectProviderFactoryImpl.java:218)
                at org.datanucleus.ExecutionContextImpl.persistObjectInternal(ExecutionContextImpl.java:1986)
                at org.datanucleus.ExecutionContextImpl.persistObjectWork(ExecutionContextImpl.java:1830)
                at org.datanucleus.ExecutionContextImpl.persistObject(ExecutionContextImpl.java:1685)
                at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:712)
                at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:738)
                at com.advantagegroup.blue.ui.jdo._BlueJdo.insert(_BlueJdo.java:40)
                at ...

This error makes sense in a way, because org.json.simple.JSONObject extends Map. However, this field is not part of any relationships -- it is of type JSON and therefore it is natural to back it with JSONObject

How do I tell JDO / DataNucleus to chill and treat org.json.simple.JSONObject the same way it would a String or a Date?

Thanks! DC

5
  • Since it is not a recognized type, have you thought of provide a JDO "AttributeConverter" for it ? Commented Mar 10, 2017 at 18:27
  • I tried that, but even with a converter DataNucleus is still looking for a related table. The problem is not that I can't save the field; the problem is that JDO automatically thinks the fields is part of a many-to-many mapping -- which it is not. I can't figure out how to tell JDO that this field does not map to other classes/tables. Commented Mar 10, 2017 at 18:56
  • So post it in your question? and post the stack trace then someone who knows the code can tell you WHY Commented Mar 10, 2017 at 18:59
  • Ummm I did put that error message in the question. I've updated the pst to include the stack trace for completeness. Commented Mar 10, 2017 at 19:04
  • For completeness: if I try to add an AttributeConverter to the field, like so: @Convert( value=JSONConverter.class ) public JSONObject category_name_localization = new JSONObject(); Then during enhancement/ process fails: Nested Throwables StackTrace: java.lang.NullPointerException at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011) at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006) at org.datanucleus.store.types.TypeManagerImpl.registerConverter(TypeManagerImpl.java:457) at ... Commented Mar 10, 2017 at 19:54

1 Answer 1

2

My understanding of this is that your default attempt is trying to persist a normal Map (since while it doesnt know what a JSONObject is, it does know what a Map is), and it will need a join table for that for RDBMS.

Since you presumably want the JSONObject persisted into a single column then you need to create a JDO AttributeConverter. I've done similar things with my own types and it works fine (i'm on v5.0.5 IIRC).

I also found this in their docs, for when you have your own Map class that it doesn't know how to handle by default in terms of replacing it with a proxy (to intercept the calls to put, putAll etc). If you add that line it will not try to wrap this field with a proxy (which it doesn't know how to do for that type, unless you tell it). If you wanted to auto-detect the JSONObject becoming "dirty" you would need to write a proxy wrapper, as per this page.

This doesn't answer how to map the column for that converter to use a "json" type in PostgreSQL, but i'd guess that if you set the sqlType you may get success in that respect.

Sign up to request clarification or add additional context in comments.

1 Comment

Implementing a converter alone did not work very well. However, with a wrapper, everything worked perfectly!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.