Modeling an RDF Resource#

The following content highlights the key modifications to a Java class to convert it into an RDF resource class. As a starting point, consider a non-RDF class Expense. Such a class may be implemented similarly to the following sample code:

// Non-RDF Class

public class Expense {
    private UUID _id;
    private Date date;
    private String description;
    // ... Additional fields

    public Expense() {

    }

    public Expense(date, description, //...) {

       this.date = date;
       this.description = descriptions;
       //...
    }

    public Date getDate() {
         return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    // ... Additional getters/setters and other content

}

1. Extend the SolidRDFSource#

The SolidRDFSource class maps to an RDF resource. A summary of parameters to the SolidRDFSource class constructors are as follows: [1]

Field

Type

Description

identifier

java.net.URI

The URI (Uniform Resource Identifier) of the resource.

dataset

org.apache.commons.rdf.api.Dataset

The RDF dataset (i.e., the set(s) of triples) contained in the resource.

headers

com.inrupt.client.Headers

Collection of HTTP headers.

To model the Expense class as an RDF resource, the class:

public class Expense extends SolidRDFSource {

   private final Node subject;
   // ...

   public Expense(final URI identifier, final Dataset dataset, final Headers headers) {
       super(identifier, dataset, headers);
       // ...
   }

   public Expense(final URI identifier) {
       this(identifier, null, null);
   }

   public Expense(final URI identifier,
                  String merchantProvider,
                  Date expenseDate,
                  String description,
                  BigDecimal amount,
                  String currency,
                  String category) {
       this(identifier, null, null);
       //...
   }
}

2. Inner Class that Extends WrapperIRI#

A sample RDF file that for a sample Expense data is shown below in Turtle format:

<https://pod.example.com/container/expenses/202303/teamlunch>
     <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>   <https://schema.org/Invoice> ;
     <https://schema.org/purchaseDate>    "2023-03-07T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
     <https://schema.org/provider>        "Example Restaurant" ;
     <https://schema.org/description>     "Team Lunch" ;
     <https://schema.org/category>        "Travel and Entertainment" ;
     <https://schema.org/priceCurrency>   "USD" ;
     <https://schema.org/totalPrice>      "120"^^<http://www.w3.org/2001/XMLSchema#decimal> ;
     <https://schema.org/image>           <https://pod.example.com/container/expenses/202303/receipt1.jpg> .

where:

subject

URL

  • <https://pod.example.com/container/expenses/202303/teamlunch>

predicates

URL

  • <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>

  • <https://schema.org/purchaseDate>

  • <https://schema.org/provider>

  • etc.

objects

Literals or URLS

  • "2023-03-07T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>

  • "Example Restaurant",

  • <https://pod.example.com/container/expenses/202303/receipt1.jpg>

  • etc.

To handle the mapping of the expense data (date, provider, description, category, priceCurrency, total) to RDF triples (<subject> <predicate> <object>):

  • The Expense class defines the predicate IRIs. That is, instead of having a Class field named date, for the RDF Resource, the value of the field is mapped to the IRI "https://schema.org/purchaseDate".

  • The Expense class defines an inner class Node that extends the WrapperIRI class.

public class Expense extends SolidRDFSource {

   // ...
    static IRI SCHEMA_DATE = rdf.createIRI("https://schema.org/purchaseDate");
    static IRI SCHEMA_PROVIDER = rdf.createIRI("https://schema.org/provider");
    static IRI SCHEMA_DESCRIPTION = rdf.createIRI("https://schema.org/description");
    static IRI SCHEMA_TOTAL_PRICE = rdf.createIRI("https://schema.org/totalPrice");
    static IRI SCHEMA_CURRENCY = rdf.createIRI("https://schema.org/priceCurrency");
    static IRI SCHEMA_CATEGORY = rdf.createIRI("https://schema.org/category");
    static IRI SCHEMA_IMAGE = rdf.createIRI("https://schema.org/image");

    // ...

    class Node extends WrapperIRI {

       Node(final RDFTerm original, final Graph graph) {
           super(original, graph);
       }

       URI getRDFType() {
           return anyOrNull(RDF_TYPE, ValueMappings::iriAsUri);
       }

       void setRDFType(String type) {
           overwriteNullable(RDF_TYPE, type, TermMappings::asIri);
       }

       String getMerchantProvider() {
           return anyOrNull(SCHEMA_PROVIDER, ValueMappings::literalAsString);
       }


      String getMerchantProvider() {
          return anyOrNull(SCHEMA_PROVIDER, ValueMappings::literalAsString);
      }

      void setMerchantProvider(String provider) {
          overwriteNullable(SCHEMA_PROVIDER, provider, TermMappings::asStringLiteral);
      }

      // ...

    }
}

Add the Inner Class Field to the RDF Resource Class#

To use the defined mappings in the inner class:

  • Update Expense.java to include a new field subject set to the inner class Node.

  • Update the Expense.java getters and setters to use the subject‘s getters and setters.

public class Expense extends SolidRDFSource {

   // ...


    private final Node subject;

    // ...

    public URI getRDFType() {
        return subject.getRDFType();
    }

    public void setRdfType(String rdfType) {
        subject.setRDFType(rdfType);
    }

    public String getMerchantProvider() {
        return subject.getMerchantProvider();
    }

    public void setMerchantProvider(String merchantProvider) {
        subject.setMerchantProvider(merchantProvider);
    }

    public Date getExpenseDate() {
        return subject.getExpenseDate();
    }

    public void setExpenseDate(Date expenseDate) {
        subject.setExpenseDate(expenseDate);
    }

    //...

}