Here is a very minimal test of what I am seeing.

Two data maps: Main and Errors.

I have an APP_USER DbTable in the Main data map and an APP_ERROR DbTable in the 
Errors data map.

Then I have a to-many relationship and inverse to one between these two.

APP_USER <->> APP_ERROR

I then simply create the ObjEntity, ObjAttribute and ObjRelationship objects 
programmatically.

I then save the first  data map and it throws a NullPointerException.  

Here is the isolated test:

(I avoided creating data nodes and the project in this code to keep things 
simple and illustrate the NullPointerException)

package play.cay.utils.conversion;

import java.io.PrintWriter;
import java.sql.Types;

import org.apache.cayenne.configuration.EmptyConfigurationNodeVisitor;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.util.XMLEncoder;

public class DataMapTest {

    public static void main(String[] args) {
        // Create DataMaps
        DataMap mainMap = new DataMap("Main");
        DataMap errorsMap = new DataMap("Errors");

        // -------------------- DB Entities --------------------

        // APP_USER DbEntity
        DbEntity appUserDb = new DbEntity("APP_USER");
        DbAttribute appUserIdDbAttr = new DbAttribute("ID", Types.INTEGER, 
appUserDb);
        appUserIdDbAttr.setPrimaryKey(true);
        appUserDb.addAttribute(appUserIdDbAttr);
        appUserDb.addAttribute(new DbAttribute("NAME", Types.VARCHAR, 
appUserDb));
        appUserDb.addAttribute(new DbAttribute("EMAIL", Types.VARCHAR, 
appUserDb));
        appUserDb.getPrimaryKeyGenerator();

        // APP_ERROR DbEntity
        DbEntity appErrorDb = new DbEntity("APP_ERROR");
        DbAttribute appErrorIdDbAttr = new DbAttribute("ID", Types.INTEGER, 
appErrorDb);
        appErrorDb.addAttribute(appErrorIdDbAttr);
        appErrorDb.addAttribute(new DbAttribute("APP_USER_ID", Types.INTEGER, 
appErrorDb));
        appErrorDb.addAttribute(new DbAttribute("ERROR_MESSAGE", Types.VARCHAR, 
appErrorDb));

        // Add DbEntities to respective maps
        mainMap.addDbEntity(appUserDb);
        errorsMap.addDbEntity(appErrorDb);

        // -------------------- DB Relationships --------------------

        // APP_ERROR -> APP_USER (to-one)
        DbRelationship toUserRel = new DbRelationship("appUser");
        toUserRel.setSourceEntity(appErrorDb);
        toUserRel.setTargetEntityName(appUserDb);
        toUserRel.setToMany(false);
        toUserRel.addJoin(new DbJoin(toUserRel, "APP_USER_ID", "ID"));
        appErrorDb.addRelationship(toUserRel);

        // APP_USER ->> APP_ERROR (to-many)
        DbRelationship errorsRel = new DbRelationship("errors");
        errorsRel.setSourceEntity(appUserDb);
        errorsRel.setTargetEntityName(appErrorDb);
        errorsRel.setToMany(true);
        errorsRel.addJoin(new DbJoin(errorsRel, "ID", "APP_USER_ID"));
        appUserDb.addRelationship(errorsRel);

        // -------------------- ObjEntities --------------------

        // APP_USER ObjEntity
        ObjEntity appUserObj = new ObjEntity("AppUser");
        appUserObj.setDbEntity(appUserDb);
        appUserObj.addAttribute(new ObjAttribute("id", "java.lang.Integer", 
appUserObj));
        appUserObj.addAttribute(new ObjAttribute("name", "java.lang.String", 
appUserObj));
        appUserObj.addAttribute(new ObjAttribute("email", "java.lang.String", 
appUserObj));

        // APP_ERROR ObjEntity
        ObjEntity appErrorObj = new ObjEntity("AppError");
        appErrorObj.setDbEntity(appErrorDb);
        appErrorObj.addAttribute(new ObjAttribute("id", "java.lang.Integer", 
appErrorObj));
        appErrorObj.addAttribute(new ObjAttribute("errorMessage", 
"java.lang.String", appErrorObj));

        // Add ObjEntities to respective maps
        mainMap.addObjEntity(appUserObj);
        errorsMap.addObjEntity(appErrorObj);

        // -------------------- ObjRelationships --------------------

        // AppError → AppUser (to-one)
        ObjRelationship appUserRel = new ObjRelationship("appUser");
        appUserRel.setSourceEntity(appErrorObj);
        appUserRel.setTargetEntityName(appUserObj); // sets target name
        appUserRel.setDbRelationshipPath("appUser");
        appErrorObj.addRelationship(appUserRel);

        // AppUser → AppError (to-many)
        ObjRelationship errorsRelObj = new ObjRelationship("errors");
        errorsRelObj.setSourceEntity(appUserObj);
        errorsRelObj.setTargetEntityName(appErrorObj); // sets target name
        errorsRelObj.setDbRelationshipPath("errors");
        appUserObj.addRelationship(errorsRelObj);
        
        PrintWriter stdout = new PrintWriter(System.out, true);
        XMLEncoder encoder = new XMLEncoder(stdout, "\t", "11");
        EmptyConfigurationNodeVisitor visitor = new 
EmptyConfigurationNodeVisitor();
        
        stdout.println(mainMap.getName());
        stdout.println();
        encoder.nested(mainMap, visitor);
        
        stdout.println();
        stdout.println();
        
        stdout.println(errorsMap.getName());
        stdout.println();
        encoder.nested(errorsMap, visitor);

    }
}

 

> 
> On Oct 14, 2025, at 3:29 PM, Ricardo Parada <[email protected]> wrote:
> 
> Hello,
> 
> I wrote a converter to convert our eomodels from EOF to Cayenne-project.xml 
> and data maps .map.xml
> 
> So far so good. However, I seem to be running into a problem for cross data 
> map relationships.
> 
> I’m using 5.0-M1.
> 
> When I’m creating the ObjRelationship I call:
> 
> objRel.setTargetEntityName(targetObjEntity);
> 
> If I then call objRel.getTargetEntityName() it returns the correct target 
> entity name.  
> 
> However, if I call objRel.getTargetEntity() it returns null.
> 
> I debugged the code and I can see that getTargetEntity() is looking for the 
> target entity name in the data map corresponding to the source ObjEntity. And 
> it does not find it and returns null for that reason.
> 
> As a result of that, when I call encodeAsXML() on objRel I see that the XML 
> is missing the target attribute in the obj-relationship xml tag.
> 
> Is this a bug in 5.0-M1 or am I missing something when creating my 
> ObjRelationship programmatically.
> 
> I could put all eomodels that have cross eomodel relationships into the same 
> data map to avoid this problem.
> 
> But when I create it in Cayenne Modeler 4.3.3 it seems to work. I see the 
> obj-relationship in the XML have target correctly set.
> 
> Thank you all in advance.
> Ricardo Parada

Reply via email to