Skip to content

Allow different source and target types in relationships #11

@kornelrabczak

Description

@kornelrabczak

Problem

The @RelationshipEntity annotation currently requires source and target nodes to be of the same type via the nodeType attribute. This prevents modeling relationships between different entity types, which is a common graph database use case.

Current Limitation

@RelationshipEntity(
    type = "KNOWS",
    nodeType = Person.class,  // Both source AND target must be Person
    sourceField = "from",
    targetField = "to"
)
public class Knows {
    Person from;
    Person to;
}

This works for same-type relationships, but fails for cross-entity relationships:

// NOT POSSIBLE with current API
@RelationshipEntity(
    type = "WORKS_AT",
    nodeType = ???,  // Can't specify both Person and Company
    sourceField = "employee",
    targetField = "employer"
)
public class Employment {
    Person employee;
    Company employer;
    LocalDate startDate;
}

Proposed Solution

Replace the single nodeType attribute with separate sourceType and targetType attributes:

@RelationshipEntity(
    type = "WORKS_AT",
    sourceType = Person.class,
    targetType = Company.class,
    sourceField = "employee",
    targetField = "employer"
)
public class Employment {
    @Id
    private String id;
    private Person employee;
    private Company employer;
    private LocalDate startDate;
}

For backward compatibility, keep nodeType as an alias when source and target are the same:

// Shorthand for sourceType = Person.class, targetType = Person.class
@RelationshipEntity(
    type = "FRIEND_OF",
    nodeType = Person.class,
    sourceField = "from",
    targetField = "to"
)
API Changes
@RelationshipEntity Annotation
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RelationshipEntity {
    String type() default "";
    /**
     * @deprecated Use sourceType and targetType instead
     */
    @Deprecated
    Class<?> nodeType() default Void.class;
    Class<?> sourceType();
    Class<?> targetType();
    String sourceField();
    String targetField();
}

RelationshipMetadata Updates

public class RelationshipMetadata<R> {
    private final Class<?> sourceType;  // Already exists
    private final Class<?> targetType;  // Already exists, but currently same as sourceType
    
    // Constructor should read sourceType/targetType from annotation
    // Fall back to nodeType for backward compatibility
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions