Working with inheritance
In this section, we'll show another important aspect of the Object to Triple Mapping support of the Topaz library.
Both RDFS and OWL, defines classes of graph nodes mainly by denoting the classes using the rdf:type property. A class can have multiple such properties and provides for sub-class, super-class relationship definitions amongst these properties.
On the other hand, in Java, the notion of multiple-inheritance is represented using interfaces. However the limitation comes from having to define an implementation class that provides concrete implementation of a set of interfaces.
Currently Topaz can instantiate objects for classes of concrete implementations only. It cannot create synthetic/proxy instances based on just an interface or an 'abstract' class alone. This may change in a future version of Topaz.
Topaz inheritance support:
- Multiple rdf:type values in @Entity
- interfaces can be annotated the same way as POJOs.
- sub-classes or concrete implementation of interfaces may refine the data-type of a property as long as it follows the Type erasure rules.
- interfaces may be used anywhere a POJO is used
- In addition to the properties that are inherited from a base class or interface, topaz also inherits the named-graph definitions from the @Entity annotation. However there can only be one graph definition for an entity and therefore conflicting graph definitions inherited from the super-class or interfaces will be flagged as an error.
Creating a base-class FoafAgent for FoafPerson
If you notice our FoafPerson class, it has both foaf:Agent and foaf:Person as its rdf:type. So an easy conversion here is to create a FoafAgent class and use that as a super class for FoafPerson. Such a change will not require any conversion of existing data and demonstrates the ease of setting up inheritence hierarchies. The changes to FoafPerson class are:
@@ -1,29 +1,18 @@ package org.topazproject.examples.photo; -import java.net.URI; import java.util.HashSet; import java.util.Set; import org.topazproject.otm.CascadeType; import org.topazproject.otm.annotations.Entity; -import org.topazproject.otm.annotations.GeneratedValue; -import org.topazproject.otm.annotations.Id; import org.topazproject.otm.annotations.Predicate; -import org.topazproject.otm.annotations.UriPrefix; -@Entity(graph="foaf", types={"foaf:Person", "foaf:Agent"}) -@UriPrefix("foaf:") -public class FoafPerson { - private URI id; +@Entity(types={"foaf:Person"}) +public class FoafPerson extends FoafAgent { private String givenname, surname; private Set<Photo> myPhotos = new HashSet<Photo>(); private Set<Photo> depictedIn = new HashSet<Photo>(); - public URI getId() {return id;} - @Id - @GeneratedValue(uriPrefix="foaf:Person/Id/")
Changes to note here are:
- the 'graph' definition in @Entity is pulled uo
- rdf:type is only foaf:Person
- @UriPrefix? is now inherited from base class
- the @Id property is moved up
And the new FoafAgent class now looks like this:
!#java
package org.topazproject.examples.photo;
import java.net.URI;
import org.topazproject.otm.annotations.Entity;
import org.topazproject.otm.annotations.GeneratedValue;
import org.topazproject.otm.annotations.Id;
import org.topazproject.otm.annotations.Predicate;
import org.topazproject.otm.annotations.UriPrefix;
@Entity(graph="foaf", types={"foaf:Agent"})
@UriPrefix("foaf:")
public class FoafAgent {
private URI id;
private String mbox;
public URI getId() {return id;}
@Id
@GeneratedValue(uriPrefix="foaf:Agent/Id/")
public void setId(URI id) {this.id = id;}
public String getMbox() { return mbox; }
@Predicate
public void setMbox(String mbox) { this.mbox = mbox; }
}
No other changes are required to the rest of the application. If you compile, build and run this, the behavior of the applicatuon will be exactly same before we did the above refactoring.
