Matthew Shaw
Matthew Shaw

Reputation: 108

neo4j ogm ambiguity in relationships using interfaces

I'm working with neo4j ogm version 2.1.1 and I am receiving the following error when modelling a relationship between two classes of the same type:

AmbiguousBaseClassException: Multiple classes found in type hierarchy that map to: [Package, Namespace, TypedElement, PackageableElement, NamedElement, Element, NetworkNode]

My scenario is that I have multiple classes that implement the PackageableElement interface, such as a package and a class. The relationship of a PackageableElement can have one or more PackageableElements exits.

Eg. A Package contains many Classes. The relationship seems to persist ok, but upon retrieval the error above is thrown.

Reading the docs, if I have understood the "ambiguity in relationships" issue, I have modified the relationship in this case with Package to use the type of "UNDIRECTED" so that the relationship is navigable in both directions. This has not solved the problem. I've pasted 3 domain objects below to show my relationship.

The structure is a Package inherits from Namespace, which implements the PackageableElement interface which has the method and annotation: @org.neo4j.ogm.annotation.Relationship(type = "HasPackageableElement", direction = org.neo4j.ogm.annotation.Relationship.UNDIRECTED) public Set getPackageableElements();

Package entity

@NodeEntity
@JsonTypeName("Package")
public class Package extends Namespace {

public String getURI() {
    return URI;
}

public void setURI(String URI) {
    this.URI = URI;
}

String URI;

@Override
public Integer getSequence() {
    return sequence;
}

@Override
public void setSequence(Integer sequence) {
    this.sequence = sequence;
}

@Index
Integer sequence;

}

Namespace class

@NodeEntity
public class Namespace implements PackagebleElement {

@Override
public Long getId() {
    return id;
}

@Override
public void setId(Long id) {
    this.id = id;
}

@GraphId
private Long id;

@Override
public Set<Comment> getComments() {
    return comments;
}

@Override
public void setComments(Set<Comment> comments) {
    this.comments = comments;
}

private Package owningPackage;

@Override
public Package getOwningPackage() {
    return owningPackage;
}

@org.neo4j.ogm.annotation.Relationship(type = "HAS_COMMENT", direction = org.neo4j.ogm.annotation.Relationship.OUTGOING)
Set<Comment> comments;

@Override
public String getName() {
    return name;
}

@Override
public void setName(String name) {
    this.name = name;
}

@Index
private String name;

@Override
public VisibilityKindEnum getVisibility() {
    return visibility;
}

@Override
public void setVisibility(VisibilityKindEnum visibility) {
    this.visibility = visibility;
}

private VisibilityKindEnum visibility;

Object type;

@Override
public Object getType() {
    return type;
}

@Override
public void setType(Object type) {
    this.type = type;
}

@Override
public Integer getSequence() {
    return sequence;
}

@Override
public void setSequence(Integer sequence) {
    this.sequence = sequence;
}

@Index
Integer sequence;

public static enum ElementTypeEnum {

    Class,
    Package;
}

@Override
public Set<PackageableElement> getPackageableElements() {
    if (packageableElements == null)
        packageableElements = new HashSet<PackageableElement>();
    return packageableElements;
}

@org.neo4j.ogm.annotation.Relationship(type = "HasPackageableElement", direction = Relationship.UNDIRECTED)
public void setPackageableElements(Set<PackageableElement> packageableElements) {
    this.packageableElements = packageableElements;
}

@org.neo4j.ogm.annotation.Relationship(type = "HasPackageableElement", direction = Relationship.UNDIRECTED)
Set<PackageableElement> packageableElements;
}

PackageableElement class

@NodeEntity
public interface PackageableElement extends NamedElement {

@org.neo4j.ogm.annotation.Relationship(type = "HasPackageableElement", direction = org.neo4j.ogm.annotation.Relationship.UNDIRECTED)
public Set<PackageableElement> getPackageableElements();

public Integer getSequence();

public void setSequence(Integer sequence);

}

I've debugged the resolve method of the MetaData class in ogm and it appears to be a bug to me. The line which reads if (taxonClassInfo.isInterface()) { LOGGER.debug("label is on an interface. Looking for a single implementing class..."); taxonClassInfo = findSingleImplementor(taxon);

The findSingleImplementor method is returning results where I have an interface extending another interface. In my scenario, NamedElement interface extends Element interface. This is then adding an > 1 entry to the resolved array which is then throwing the error.

Is this the correct behaviour? I would've thought it should be looking for concrete implementations.

Upvotes: 1

Views: 505

Answers (1)

michaeak
michaeak

Reputation: 1669

After doing some refactoring in my working project I had an exception AmbiguousBaseClassException like this using neo4j-ogm version 2.1.2.

I found out that for my particular problem the concrete Class was scanned, but the generic class was not scanned, i.e. when I created the SessionFactory, the packages I listed where not containing the base class.

In particular I had a class named BaseObject (base class). It was extended by the concrete class Person.

After adding the package in which BaseObject was contained, when creating the SessionFactory, the exception was gone.

Upvotes: 1

Related Questions