001package org.w3.ldp.testsuite.mapper; 002 003import java.io.ByteArrayOutputStream; 004import java.io.InputStream; 005import java.io.UnsupportedEncodingException; 006 007import org.apache.jena.atlas.json.JSON; 008import org.apache.jena.atlas.json.JsonArray; 009import org.apache.jena.atlas.json.JsonObject; 010import org.apache.jena.atlas.json.JsonValue; 011import org.w3.ldp.testsuite.http.MediaTypes; 012import org.w3.ldp.testsuite.matcher.HeaderMatchers; 013 014import com.hp.hpl.jena.rdf.model.Model; 015import com.hp.hpl.jena.rdf.model.ModelFactory; 016import com.hp.hpl.jena.rdf.model.RDFWriter; 017import com.jayway.restassured.mapper.ObjectMapper; 018import com.jayway.restassured.mapper.ObjectMapperDeserializationContext; 019import com.jayway.restassured.mapper.ObjectMapperSerializationContext; 020 021public class RdfObjectMapper implements ObjectMapper { 022 023 private String baseURI; 024 025 public RdfObjectMapper() { 026 this.baseURI = ""; 027 } 028 029 public RdfObjectMapper(String baseURI) { 030 this.baseURI = baseURI; 031 } 032 033 private String getLang(String mediaType) { 034 if (HeaderMatchers.isTurtleCompatibleContentType().matches(mediaType)) { 035 return "TURTLE"; 036 } else if (MediaTypes.APPLICATION_RDF_XML.equals(mediaType)) { 037 return "RDF/XML"; 038 } else if (MediaTypes.APPLICATION_JSON.equals(mediaType) || 039 MediaTypes.APPLICATION_LD_JSON.equals(mediaType)) { 040 return "JSON-LD"; 041 } 042 043 throw new IllegalArgumentException("Unsupported media type: " + mediaType); 044 } 045 046 @Override 047 public Object deserialize(ObjectMapperDeserializationContext context) { 048 InputStream input = context.getDataToDeserialize().asInputStream(); 049 Model m = ModelFactory.createDefaultModel(); 050 m.read(input, baseURI, getLang(context.getContentType())); 051 return m; 052 } 053 054 @Override 055 public Object serialize(ObjectMapperSerializationContext context) { 056 Model model = context.getObjectToSerializeAs(Model.class); 057 ByteArrayOutputStream out = new ByteArrayOutputStream(); 058 059 String lang = getLang(context.getContentType()); 060 RDFWriter rdfWriter = model.getWriter(lang); 061 rdfWriter.setProperty("relativeURIs", "same-document"); 062 rdfWriter.setProperty("allowBadURIs", "true"); 063 rdfWriter.write(model, out, baseURI); 064 065 if ("JSON-LD".equals(lang)) { 066 // Do some additional processing to simplify the JSON-LD if 067 // possible and remove Jena's urn:x-arq:DefaultGraphNode. 068 try { 069 JsonObject json = JSON.parse(out.toString("UTF-8")); 070 JsonValue graph = json.get("@graph"); 071 JsonValue jsonContext = json.get("@context"); 072 if (graph != null && graph.isArray()) { 073 out = new ByteArrayOutputStream(); 074 JsonArray a = graph.getAsArray(); 075 076 if (a.size() == 1) { 077 // If size is 1, @graph isn't necessary. 078 JsonObject content = a.get(0).getAsObject(); 079 if (jsonContext != null) { 080 // Preserve the context if it's there. 081 content.put("@context", jsonContext); 082 } 083 084 JSON.write(out, content); 085 } else { 086 // Remove graph ID urn:x-arq:DefaultGraphNode. If @id is 087 // left out, it is the implicit default graph. 088 // See https://issues.apache.org/jira/browse/JENA-794 089 json.remove("@id"); 090 JSON.write(out, json); 091 } 092 } 093 } catch (UnsupportedEncodingException e) { 094 throw new RuntimeException(e); 095 } 096 } 097 098 return out.toByteArray(); 099 } 100}