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:

Field
Type
Description

identifier

The URI (Uniform Resource Identifier) of the resource.

dataset

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

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/expenses/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);
    }

    //...

}

Last updated