001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.rdf.serialize;
031
032import java.io.IOException;
033import java.io.StringReader;
034import java.lang.reflect.Array;
035import java.lang.reflect.Field;
036import java.lang.reflect.InvocationTargetException;
037import java.lang.reflect.Method;
038import java.lang.reflect.Type;
039import java.net.MalformedURLException;
040import java.net.URISyntaxException;
041import java.net.URL;
042import java.util.ArrayList;
043import java.util.Arrays;
044import java.util.Collection;
045import java.util.HashMap;
046import java.util.HashSet;
047import java.util.List;
048
049import org.openimaj.util.pair.IndependentPair;
050import org.openrdf.model.Statement;
051import org.openrdf.model.URI;
052import org.openrdf.model.Value;
053import org.openrdf.model.impl.LiteralImpl;
054import org.openrdf.model.impl.StatementImpl;
055import org.openrdf.model.impl.URIImpl;
056import org.openrdf.model.impl.ValueFactoryImpl;
057import org.openrdf.model.vocabulary.RDF;
058import org.openrdf.query.BindingSet;
059import org.openrdf.query.BooleanQuery;
060import org.openrdf.query.MalformedQueryException;
061import org.openrdf.query.QueryEvaluationException;
062import org.openrdf.query.QueryLanguage;
063import org.openrdf.query.TupleQuery;
064import org.openrdf.query.TupleQueryResult;
065import org.openrdf.repository.Repository;
066import org.openrdf.repository.RepositoryConnection;
067import org.openrdf.repository.RepositoryException;
068import org.openrdf.repository.sail.SailRepository;
069import org.openrdf.rio.RDFFormat;
070import org.openrdf.rio.RDFParseException;
071import org.openrdf.sail.memory.MemoryStore;
072import org.springframework.core.ResolvableType;
073
074import javassist.Modifier;
075
076/**
077 * The RDFSerializer is used to serialise an object to RDF. It will serialise
078 * the object deeply. This class itself does not output any specific RDF
079 * representation but generates triples which is gives to the method
080 * {@link #addTriple(Statement)}. This method must be overridden in a subclass
081 * to provide the actual representation output.
082 * <p>
083 * For example, to output to Turtle, you might use the OpenRDF TurtleWriter to
084 * form a representation of the RDF graph:
085 * <p>
086 * <code><pre>
087 *              StringWriter sw = new StringWriter();
088 *              final TurtleWriter tw = new TurtleWriter( sw );
089 *              RDFSerializer rs = new RDFSerializer()
090 *              {
091 *                      public void addTriple( Statement s )
092 *                      {
093 *                              tw.handleStatement( s );
094 *                      }
095 *              };
096 *              rs.serialize( myObject );
097 *              System.out.println( sw.toString() );
098 *      </pre></code>
099 * <p>
100 * By default the class will only produce triples for fields which have been
101 * annotated with the {@link Predicate} annotation. The annotation gives the URI
102 * used to link the object to its field in the triple. If you wish to attempt to
103 * serialise unannotated fields, then you should use the constructor that takes
104 * a boolean, passing true: {@link #RDFSerializer(boolean)}. This will then
105 * create predicates based on the field name, so field {@code member} will
106 * become predicate {@code hasMember}. Complex fields are serialised into
107 * subgraphs and those graphs have URIs automatically generated for them based
108 * on the URI of the object in which they exist and their name. For example:
109 * <code><pre>
110 *      http://example.com/MyObject
111 *              http://example.com/MyObject_hasMember
112 *              http://example.com/MyObject_member.
113 * </pre></code>
114 * <p>
115 * The {@link #serialize(Object, String)} method requires the URI of the object
116 * to be serialised. This must be decided by the caller and passed in. It is
117 * used to construct URIs for complex fields and predicates (if not given). So,
118 * an object with URI <code>http://example.com/object</code> and a complex field
119 * called <code>field</code> will end up with a triple that links the object to
120 * a subgraph representing the complex object as so: <code><pre>
121 *              http://example.com/object :hasField http://example.com/object_field
122 *      </pre></code> The name of the subgraph is based on the URI of the object and
123 * the name of the field. The predicate is also automatically generated from the
124 * name of the field. Note that this means you may need to be careful about the
125 * names of the fields. For example, if an object had a complex field
126 * <code>name_first</code> but also had a complex field <code>name</code> that
127 * itself had a complex field <code>first</code> it's possible the same URI may
128 * be generated for both subgraphs.
129 * <p>
130 * Primitive types will be typed with XSD datatypes. For example: <code><pre>
131 *      example:field example:hasNumber "20"^^xsd:integer
132 * </pre></code>
133 * <p>
134 * Lists and collections are output in one of two ways. By default they are
135 * output as separate triples in an unordered way: <code><pre>
136 *              &#64;Predicate("http://example.com/hasString")
137 *              String[] strings = new String[] { "one", "two" };
138 * </pre></code> ...will be output, by default, as: <code><pre>
139 *      http://example.com/object
140 *                      http://example.com/hasString "one";
141 *                      http://example.com/hasString "two".
142 * </pre></code>
143 * <p>
144 * Alternatively, the {@link RDFCollection} annotation can be used. When this
145 * annotation is used, they are encoded using RDF sequences; that is as
146 * subgraphs where the items have the predicates
147 * <code>rdf:_1, rdf:_2..., rdf:_n</code> and the type <code>rdf:Seq</code>.
148 * This retains the same order for the collection as when serialised. So the
149 * above example would be output as: <code><pre>
150 *      http://example.com/object
151 *              http://example.com/hasString http://example.com/strings .
152 *      http://example.com/strings
153 *              rdf:type        rdf:Seq;
154 *              rdf:_1  "one";
155 *              rdf:_2  "two".
156 * </pre></code>
157 * <p>
158 * By default the serialisation will also output a triple that gives the class
159 * name of the object which is being serialised. If you do not want this, use
160 * the {@link #setOutputClassNames(boolean)} to turn it off, although this may
161 * cause the deserialization to stop working, if the original fields in the
162 * object are defined as non-concrete classes (e.g. List or Collection rather
163 * than an ArrayList). In this case, the deserialiser attempts to look for this
164 * triple to find the actual class that was serialised.
165 * <p>
166 * The {@link RelationList} annotation allows collections of independent pairs
167 * of URI and Object can be sent to the RDF graph directly without validation.
168 * This is not deserialisable as there's no way for the derserialiser to know
169 * which triples belong in this collection.
170 * <p>
171 * The {@link TripleList} annotation allows members that are collections of
172 * OpenRDF {@link Statement} objects to be sent to the RDF graph directly.
173 * Again, this is not deserialisable as there's no way for the derserialiser to
174 * know which triples belong in this collection.
175 * <p>
176 * This class also provides an unserialisation routine for converting an RDF
177 * graph back into an object graph. Given a string that is an RDF representation
178 * of a graph (serialised with the serialiser), it will return the object.
179 *
180 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
181 * @created 11 Sep 2012
182 * @version $Author$, $Revision$, $Date$
183 */
184public class RDFSerializer {
185        /** URI used for temporary graph when loading into a store */
186        public static final String RDF_OPENIMAJ_TMP_GRAPH = "http://rdf.openimaj.org/tmp/";
187
188        /** Predicate for giving the class name */
189        public static final String RDF_OPENIMAJ_P_CLASSNAME = "http://rdf.openimaj.org/hasClassName/";
190
191        /** Predicate for unnamed collections */
192        public static final String RDF_OPENIMAJ_P_COLLECTIONITEM = "http://rdf.openimaj.org/hasCollectionItem/";
193
194        /** Whether to try to create predicates for unannotated fields */
195        protected boolean autoPredicate = false;
196
197        /** Whether to output class names */
198        protected boolean outputClassNames = true;
199
200        /**
201         * During a serialization, this field contains all the graphs which have already
202         * been written, avoiding duplicate entries in the output as well as avoiding
203         * infinite loops when cycles occur
204         */
205        private HashSet<URI> knownGraphs = null;
206
207        /**
208         * Default constructor
209         */
210        public RDFSerializer() {
211                this(false);
212        }
213
214        /**
215         * Constructor that determines whether to create predicates automatically when
216         * the {@link Predicate} annotation does not exist.
217         *
218         * @param autoPredicate
219         *            Whether to automatically create predicates
220         */
221        public RDFSerializer(final boolean autoPredicate) {
222                this.autoPredicate = autoPredicate;
223        }
224
225        /**
226         * Serialize the given object as RDF.
227         *
228         * @param objectToSerialize
229         *            The object to serialize.
230         * @param uri
231         *            The URI of the object to serialize.
232         * @return Returns the URI of the object (this may be different to the one
233         *         that's passed in)
234         */
235        public URI serialize(final Object objectToSerialize, final String uri) {
236                this.knownGraphs = new HashSet<URI>();
237                final URI i = this.serializeAux(objectToSerialize, uri);
238                return i;
239        }
240
241        /**
242         * Serialize the given object as RDF.
243         *
244         * @param objectToSerialize
245         *            The object to serialize.
246         * @param uri
247         *            The URI of the object to serialize.
248         * @return Returns the URI of the object (this may be different to the one
249         *         that's passed in)
250         */
251        public URI serializeAux(final Object objectToSerialize, final String uri) {
252                return this.serializeAux(objectToSerialize, uri, true);
253        }
254
255        /**
256         * Serialize the given object as RDF. This is specifically designed for calling
257         * by the process outputting collections.
258         *
259         * @param objectToSerialize
260         *            The object to serialize.
261         * @param uri
262         *            The URI of the object to serialize.
263         * @param outputCollectionObjects
264         *            Whether to output items in a collection
265         * @return Returns the URI of the object (this may be different to the one
266         *         that's passed in)
267         */
268        public URI serializeAux(final Object objectToSerialize, final String uri,
269                        final boolean outputCollectionObjects)
270        {
271                // The subject (the object to serialize) won't change, so
272                // we'll just create the URI node once.
273                URIImpl subject = new URIImpl(uri);
274
275                // Find the object URI
276                subject = this.getObjectURI(objectToSerialize, subject);
277
278                // Check whether we've already serialized this object. If we have
279                // we just return, otherwise we add it to our memory of serialized
280                // objects so that we won't try again.
281                if (this.knownGraphs.contains(subject))
282                        return subject;
283
284                this.knownGraphs.add(subject);
285
286                // Output the class name of the object to serialise
287                if (this.outputClassNames)
288                        this.addTriple(new StatementImpl(subject, new URIImpl(
289                                        RDFSerializer.RDF_OPENIMAJ_P_CLASSNAME),
290                                        this
291                                                        .checkPrimitive(objectToSerialize.getClass().getName())));
292
293                // Check whether there's a semantic type for this object
294                final RDFType typeAnnotation = objectToSerialize.getClass()
295                                .getAnnotation(RDFType.class);
296
297                // If there is a type anotation, add it as a triple in the graph.
298                if (typeAnnotation != null)
299                        this.addTriple(new StatementImpl(subject, RDF.TYPE, new URIImpl(
300                                        typeAnnotation.value())));
301
302                // If this top-level object is a collection, we obviously
303                // have no predicate for all the items in the collection,
304                // so we will output them all linked to the subject URI by
305                // way of the OpenIMAJ hasCollectionItem predicate. This functionality
306                // can be disabled by passing in outputCollectionObjects as false,
307                // which the processCollection() method does when serializing collections.
308                // It does this because it will have already output the list items for
309                // a collection object, but will have recursed here to allow the other
310                // fields in the collection object to be serialized.
311                if (objectToSerialize instanceof Collection && outputCollectionObjects) {
312                        this.processCollection(subject, new URIImpl(RDFSerializer.RDF_OPENIMAJ_P_COLLECTIONITEM),
313                                        subject, "", objectToSerialize, false);
314
315                        // We will still carry on and serialize the other parts
316                        // of this object...
317                }
318
319                // Get all the fields
320                final List<Field> fields = this.getAllFields(objectToSerialize);
321
322                // Loop through the fields and output them one at a time
323                for (final Field field : fields) {
324                        // We won't output static members
325                        if (Modifier.isStatic(field.getModifiers()))
326                                continue;
327
328                        // System.out.println( "====== Field "+field+" ============");
329
330                        try {
331                                // Get the value of the field
332                                field.setAccessible(true);
333                                final Object oo = field.get(objectToSerialize);
334
335                                // Special fields have annotations which mean they will be
336                                // output in some other way, as defined in the outputSpecial()
337                                // method. If this field is not one of those, we'll output
338                                // in the normal way.
339                                if (!this.outputSpecial(oo, field, subject)) {
340                                        // Get the predicate name (may be null if if cannot be
341                                        // created either due to a lack of the @Predicate
342                                        // annotation or because autoPredicate is false
343                                        final URIImpl predicate = this.getPredicateName(field, uri);
344
345                                        // If the predicate is null, we can't output this object.
346                                        // Otherwise, we'll go ahead and output it.
347                                        if (predicate != null)
348                                                this.processObject(subject, predicate, field.getName(), oo,
349                                                                field.getAnnotation(RDFCollection.class) != null);
350                                }
351                        } catch (final Exception e) {
352                                System.out.println("Error reflecting " + field);
353                                e.printStackTrace();
354                        }
355                }
356
357                return subject;
358        }
359
360        /**
361         * Serialises a single object into the graph using the given subject and
362         * predicate in the triple.
363         *
364         * @param subject
365         *            The URI of the subject being serialised
366         * @param predicate
367         *            The URI of the predicate for this member
368         * @param field
369         *            The name of the field being serialised
370         * @param oo
371         *            The object being serialised
372         * @param asCollection
373         *            Whether the field should be output as an {@link RDFCollection}
374         */
375        private void processObject(final URIImpl subject, final URIImpl predicate,
376                        final String fieldName, final Object oo, final boolean asCollection)
377        {
378                // Get the URI of the subject (the object we're serialising)
379                final String uri = subject.stringValue();
380
381                // If the value of the object to output is not null, we go ahead
382                // and serialise the object.
383                if (oo != null && predicate != null) {
384                        // This will be the value of the object we're outputting.
385                        // It'll be a URI for complex objects.
386                        Value object;
387
388                        // This value will give whether we're outputting a collection object.
389                        // That also includes Arrays.
390                        boolean isCollective = false;
391
392                        // Check if we should output a primitive value. If so, we're done.
393                        // Otherwise, we'll need to do some more complex analysis...
394                        if ((object = this.checkPrimitive(oo)) == null) {
395                                // Get a URI for this object
396                                final URIImpl objectURI = this.getObjectURI(
397                                                oo, new URIImpl(
398                                                                subject.stringValue() + "_" + fieldName));
399
400                                // If oo is an array, we'll call the processArray() method
401                                // to output it. The object becomes a URI to the array subgraph.
402                                if (oo.getClass().isArray()) {
403                                        isCollective = true;
404                                        object = this.processArray(subject, predicate, objectURI,
405                                                        fieldName, oo, asCollection);
406                                } else
407                                // If we have a collection of things, we'll output
408                                // them as an RDF linked-list. The object becomes a URI
409                                // to the collection's subgraph.
410                                if (oo instanceof Collection<?>) {
411                                        isCollective = true;
412                                        object = this.processCollection(subject, predicate, objectURI,
413                                                        fieldName, oo, asCollection);
414                                }
415                                // Not a primitive, array or collection? Must be a
416                                // regular object, so we'll recurse this process with
417                                // the value of the field.
418                                else {
419                                        // The URI is the uri of the subject concatenated
420                                        // with the name of the field from which this value
421                                        // was taken.
422                                        object = new URIImpl(uri + "_"
423                                                        + fieldName);
424
425                                        // Here's the recursive call to the process
426                                        object = this.serializeAux(oo, object.stringValue());
427                                }
428                        }
429
430                        // We don't need to add this triple if the triples are a
431                        // are collection that's been output separately
432                        if (!isCollective || (isCollective && asCollection)) {
433                                // Create a triple and send it to the serializer
434                                final Statement t = new StatementImpl(subject,
435                                                predicate, object);
436                                this.addTriple(t);
437                        }
438                }
439        }
440
441        /**
442         * Processes an array object outputting triples for the entire array. Returns
443         * the Value linking to this array.
444         *
445         * @param subject
446         *            The URI of the object to serialise
447         * @param predicate
448         *            The predicate between the subject and this array
449         * @param collectionURI
450         *            The URI of the collection subgraph
451         * @param field
452         *            The field in the object that's the array
453         * @param arrayObject
454         *            The array object
455         * @param asCollection
456         *            Whether to output as an RDF Collection
457         * @return The object linking to this array
458         */
459        private Value processArray(final URIImpl subject, final URIImpl predicate,
460                        final URIImpl collectionURI, final String fieldName,
461                        final Object arrayObject, final boolean asCollection)
462        {
463                // Loop through all the array elements and output them separately.
464                for (int count = 0; count < Array.getLength(arrayObject);) {
465                        // Get the array element value..
466                        final Object o = Array.get(arrayObject, count);
467
468                        // Call the processListitemObject to output the actual value.
469                        // We call this method rather than the serializeAux() method because
470                        // we need to deal with the various methods for outputting collections
471                        // in one single place (e.g. as a collection, or an RDF sequence, etc.)
472                        count = this.processListItemObject(subject, predicate, collectionURI,
473                                        count, o, asCollection);
474                }
475
476                return collectionURI;
477        }
478
479        /**
480         * Processes a collection object.
481         *
482         * @param subject
483         *            The URI of the object we're serializing
484         * @param predicate
485         *            The predicate for this collection
486         * @param collectionURI
487         *            The URI of the collection subgraph
488         * @param field
489         *            The field in the object that is the collection
490         * @param collectionObject
491         *            The collection object
492         * @param asCollection
493         *            Whether to output as an RDF collection
494         * @return The object created for this collection
495         */
496        private Value processCollection(final URIImpl subject, final URIImpl predicate,
497                        final URIImpl collectionURI, final String fieldName,
498                        final Object collectionObject, final boolean asCollection)
499        {
500                // Loop through all the collection items outputting them one at a time.
501                int count = 1;
502                for (final Object o : (Collection<?>) collectionObject) {
503                        // We call this method rather than the serializeAux() method because
504                        // we need to deal with the various methods for outputting collections
505                        // in one single place (e.g. as a collection, or an RDF sequence, etc.)
506                        count = this.processListItemObject(subject, predicate, collectionURI,
507                                        count, o, asCollection);
508                }
509
510                // We also need to serialize the object itself because if
511                // The collection is actually a subclass that contains
512                // @Predicate annotations we need to go ahead and
513                // serialise those too; so we recurse here.
514                final Value object = this.serializeAux(collectionObject,
515                                collectionURI.stringValue(), false);
516
517                return object;
518        }
519
520        /**
521         * A method that's called during the processing of a list of items to write a
522         * single item.
523         *
524         * @param subject
525         *            The URI of the object in which this collection exists
526         * @param predicate
527         *            The predicate of the collection in the original graph
528         * @param collectionURI
529         *            The URI of the collection in the graph
530         * @param listCounter
531         *            The current counter in the list (1-based index)
532         * @param listItemObject
533         *            The object to be serialised
534         * @param asSequence
535         *            Whether to output as an RDF Sequence or as individual triples
536         * @return the next counter in the list
537         */
538        private int processListItemObject(
539                        URIImpl subject, URIImpl predicate,
540                        final URIImpl collectionURI,
541                        final int listCounter, final Object listItemObject,
542                        final boolean asSequence)
543        {
544                // If we're outputting as a sequence, then we must
545                // alter the predicate and therefore the subject
546                if (asSequence) {
547                        // If we're outputting as an RDF sequence the predicate
548                        // becomes the rdf:_n counter predicate and the subject
549                        // will be the URI of the collection
550                        predicate = new URIImpl(RDF.NAMESPACE + "_" + listCounter);
551                        subject = collectionURI;
552                }
553
554                // Check whether the list item is a primitive. If it is, its
555                // value will be output directly into the collection, otherwise
556                // we need to output a subgraph URI instead.
557                Value oo = null;
558                oo = this.checkPrimitive(listItemObject);
559
560                // If list item isn't a primitive, get a URI for it.
561                if (oo == null) {
562                        // Get the URI for the list item object.
563                        oo = this.getObjectURI(listItemObject,
564                                        new URIImpl(collectionURI.stringValue()
565                                                        + "_listItem" + listCounter));
566
567                        // We're here because the list item is not a primitive - it's a
568                        // complex object or a collection; in which case we must
569                        // link to a subgraph and output that subgraph.
570                        this.addTriple(new StatementImpl(subject, predicate, oo));
571
572                        // Now we serialize the object into the graph
573                        this.serializeAux(listItemObject, oo.stringValue());
574                }
575                // Output the primitive triple
576                else {
577                        this.addTriple(new StatementImpl(subject, predicate, oo));
578                }
579
580                return listCounter + 1;
581        }
582
583        /**
584         * Returns a predicate name for the given field.
585         *
586         * @param field
587         *            The field
588         * @param uri
589         *            The URI of the object
590         * @return A predicate URI, either generated from the @Predicate annotation or
591         *         from the field name
592         */
593        private URIImpl getPredicateName(final Field field, final String uri) {
594                // Get the predicate annotation, if there is one
595                final Predicate predicateAnnotation = field
596                                .getAnnotation(Predicate.class);
597
598                URIImpl predicate = null;
599                if (predicateAnnotation != null) {
600                        // Create a predicate URI for this predicate
601                        predicate = new URIImpl(predicateAnnotation.value());
602                }
603                // Null predicate annotation?
604                else {
605                        // Try to create a predicate for the unannotated field
606                        if (this.autoPredicate)
607                                predicate = new URIImpl(uri + "_has"
608                                                + field.getName().substring(0, 1).toUpperCase()
609                                                + field.getName().substring(1));
610                }
611
612                return predicate;
613        }
614
615        /**
616         * Checks whether the given object is a primitive type and, if so, will return a
617         * Node that encodes it. Otherwise NULL is returned.
618         *
619         * @param o
620         *            The object to check
621         * @return a Node or NULL
622         */
623        private Value checkPrimitive(final Object o) {
624                if (o instanceof String)
625                        return new LiteralImpl(o.toString());
626
627                if (o instanceof Integer)
628                        return new ValueFactoryImpl().createLiteral((Integer) o);
629
630                if (o instanceof Float)
631                        return new ValueFactoryImpl().createLiteral((Float) o);
632
633                if (o instanceof Double)
634                        return new ValueFactoryImpl().createLiteral((Double) o);
635
636                if (o instanceof URI || o instanceof URL || o instanceof java.net.URI)
637                        return new URIImpl(o.toString());
638
639                return null;
640        }
641
642        /**
643         * Returns a list of declared fields from the whole object tree.
644         *
645         * @param o
646         *            The object
647         * @return A list of fields
648         */
649        private List<Field> getAllFields(final Object o) {
650                final ArrayList<Field> fields = new ArrayList<Field>();
651                Class<?> objectToGetFieldsFrom = o.getClass();
652                do {
653                        fields.addAll(Arrays.asList(objectToGetFieldsFrom
654                                        .getDeclaredFields()));
655                        objectToGetFieldsFrom = objectToGetFieldsFrom.getSuperclass();
656                } while (!objectToGetFieldsFrom.getSimpleName().equals("Object"));
657
658                return fields;
659        }
660
661        /**
662         * Set whether to output class names as triples.
663         *
664         * @param tf
665         *            TRUE to output class name triples.
666         */
667        public void setOutputClassNames(final boolean tf) {
668                this.outputClassNames = tf;
669        }
670
671        /**
672         * Set whether to attempt to output all fields from the objects, not just those
673         * annotated with {@link Predicate}.
674         *
675         * @param tf
676         *            TRUE to attempt to find predicates for all members.
677         */
678        public void setAutoPredicate(final boolean tf) {
679                this.autoPredicate = tf;
680        }
681
682        /**
683         * Unserializes an object from the given RDF string (with the given format) into
684         * the given object.
685         *
686         * @param <T>
687         *            Type of object being unserialised
688         *
689         * @param objectToUnserialize
690         *            The object to populate
691         * @param objectRootURI
692         *            The URI that gives the root of the object graph
693         * @param rdf
694         *            The RDF string
695         * @param rdfFormat
696         *            The format of the RDF in the string
697         * @return The populated object or NULL if an error occurs
698         */
699        public <T> T unserialize(final T objectToUnserialize,
700                        final String objectRootURI, final String rdf,
701                        final RDFFormat rdfFormat)
702        {
703                try {
704                        // We'll read the RDF into a memory store. So create that store
705                        // here.
706                        final Repository repo = new SailRepository(new MemoryStore());
707                        repo.initialize();
708
709                        // Read the RDF into the store
710                        final RepositoryConnection connection = repo.getConnection();
711                        final StringReader sr = new StringReader(rdf);
712                        final String graphURI = RDFSerializer.RDF_OPENIMAJ_TMP_GRAPH;
713                        connection.add(sr, graphURI, rdfFormat);
714
715                        // Now unserialize the object
716                        return this.unserialize(objectToUnserialize, objectRootURI, repo);
717                } catch (final RepositoryException e) {
718                        e.printStackTrace();
719                        return null;
720                } catch (final RDFParseException e) {
721                        e.printStackTrace();
722                        return null;
723                } catch (final IOException e) {
724                        e.printStackTrace();
725                        return null;
726                }
727        }
728
729        /**
730         * Unserializes an object from an RDF graph that is rooted at the given URI.
731         *
732         * @param <T>
733         *            Type of object being unserialised
734         *
735         * @param objectToUnserialize
736         *            The object to populate
737         * @param objectRootURI
738         *            The URI that gives the root of the object graph
739         * @param repo
740         *            The repository storing the RDF graph
741         * @return The populated object or NULL if an error occurs
742         */
743        public <T> T unserialize(final T objectToUnserialize,
744                        final String objectRootURI, final Repository repo)
745        {
746                // Can't do anything if the object is null
747                if (objectToUnserialize == null) {
748                        System.err.println("Unserialize error: given object is null");
749                        return null;
750                }
751
752                // If our starting object is a collection, then there will be no
753                // predicate for us to work with. So we'll get the items from the
754                // collection using the statically defined predicate
755                // RDF_OPENIMAJ_P_COLLECTIONITEM. We will still need to deserialise
756                // the object after this, in case the collection has any
757                // predicated members that need to be deserialised.
758                if (objectToUnserialize instanceof Collection<?>)
759                        this.extractCollectionDirect((Collection<?>) objectToUnserialize,
760                                        objectRootURI, repo);
761
762                try {
763                        final RepositoryConnection connection = repo.getConnection();
764
765                        // Get the fields of the object's class
766                        final Field[] fields = objectToUnserialize.getClass().getFields();
767
768                        // Loop through the fields
769                        for (final Field field : fields) {
770                                // System.out.println( "=========== Field "+field.getName()+" ============= ");
771
772                                try {
773                                        // Get the name of the predicate for this field
774                                        final URIImpl predicateName = this.getPredicateName(field,
775                                                        objectRootURI);
776
777                                        // If we can't determine a predicate, we don't unserialize it
778                                        if (predicateName != null) {
779                                                // If it's a collection, we'll do something special
780                                                if (Collection.class.isAssignableFrom(field.getType())) {
781                                                        this.unserializeCollection(field, objectToUnserialize,
782                                                                        objectRootURI, repo, predicateName);
783                                                } else
784                                                // Same goes for if it's an array.
785                                                if (((Class<?>) field.getType()).isArray()) {
786                                                        this.unserializeArray(objectToUnserialize,
787                                                                        objectRootURI, repo, field, predicateName);
788                                                }
789                                                // If we don't know what it is, we'll treat it as
790                                                // an unknown (RDF) serializable object and recurse
791                                                else {
792                                                        // Query the RDF graph for the triples that represent
793                                                        // this field in the graph. If there are more
794                                                        // than one, the first will be used.
795                                                        try {
796                                                                final String queryString = "SELECT ?o WHERE {<"
797                                                                                + objectRootURI + "> <" + predicateName
798                                                                                + "> ?o.}";
799                                                                final TupleQuery tupleQuery = connection
800                                                                                .prepareTupleQuery(QueryLanguage.SPARQL,
801                                                                                                queryString);
802                                                                final TupleQueryResult result = tupleQuery
803                                                                                .evaluate();
804
805                                                                // We only want the first result because we know
806                                                                // it's not a collection
807                                                                if (result.hasNext()) {
808                                                                        try {
809                                                                                final BindingSet bindingSet = result.next();
810                                                                                final Value objectValue = bindingSet
811                                                                                                .getValue("o");
812
813                                                                                // We have a value for the field. Now what
814                                                                                // we do with it depends on the field itself.
815                                                                                field.setAccessible(true);
816                                                                                field.set(objectToUnserialize,
817                                                                                                this.getFieldValue(
818                                                                                                                field.getGenericType(),
819                                                                                                                objectValue, repo,
820                                                                                                                field.getName(),
821                                                                                                                objectRootURI));
822                                                                        } catch (final IllegalArgumentException e) {
823                                                                                e.printStackTrace();
824                                                                        } catch (final IllegalAccessException e) {
825                                                                                e.printStackTrace();
826                                                                        }
827                                                                } else {
828                                                                        // RDF Graph did not have a value for the field
829                                                                }
830                                                        } catch (final MalformedQueryException e) {
831                                                                e.printStackTrace();
832                                                        } catch (final QueryEvaluationException e) {
833                                                                e.printStackTrace();
834                                                        }
835                                                }
836                                        }
837                                } catch (final IllegalArgumentException e) {
838                                        e.printStackTrace();
839                                } catch (final IllegalAccessException e) {
840                                        e.printStackTrace();
841                                }
842                        }
843
844                        connection.close();
845                } catch (final RepositoryException e) {
846                        e.printStackTrace();
847                } catch (final SecurityException e) {
848                        e.printStackTrace();
849                }
850
851                return objectToUnserialize;
852        }
853
854        /**
855         * @param objectToUnserialize
856         * @param objectRootURI
857         * @param repo
858         */
859        @SuppressWarnings("unchecked")
860        private <T extends Collection<?>> void extractCollectionDirect(
861                        final T objectToUnserialize,
862                        final String objectRootURI, final Repository repo)
863        {
864                final Class<?> collectionType = ResolvableType.forClass(objectToUnserialize.getClass()).asCollection()
865                                .resolveGeneric();
866
867                // TODO: This needs to be sorted out. We can't pass null.
868                // Unserialize the collection items.
869                final Object[] seq = this.extractCollectionObjects(
870                                objectRootURI, repo, collectionType,
871                                "", objectRootURI,
872                                RDFSerializer.RDF_OPENIMAJ_P_COLLECTIONITEM);
873
874                ((Collection<Object>) objectToUnserialize).clear();
875                for (int i = 0; i < seq.length; i++)
876                        ((Collection<Object>) objectToUnserialize).add(seq[i]);
877        }
878
879        /**
880         * Unserializes an array object from the graph.
881         *
882         * @param objectToUnserialize
883         *            The object in which there is an array field
884         * @param objectRootURI
885         *            The URI of the object in which there is an array field
886         * @param repo
887         *            The repository containing the RDF graph
888         * @param field
889         *            The field that is the array
890         * @param predicateName
891         *            The name of the predicate for the array items
892         * @throws IllegalAccessException
893         *             If the field cannot be set
894         */
895        private <T> void unserializeArray(final T objectToUnserialize,
896                        final String objectRootURI, final Repository repo, final Field field,
897                        final URIImpl predicateName) throws IllegalAccessException
898        {
899                final Class<?> componentType = field.getType().getComponentType();
900
901                // Go get all the array objects
902                @SuppressWarnings("unchecked")
903                final T[] seq = (T[]) this
904                                .extractCollectionObjects(objectRootURI, repo,
905                                                componentType, field.getName(),
906                                                objectRootURI, predicateName
907                                                                .stringValue());
908
909                // Set the field up
910                field.setAccessible(true);
911                field.set(objectToUnserialize, seq);
912        }
913
914        /**
915         * Unserializes a collection object from the graph. This method is mainly
916         * dealing with setting up the appropriate collection instance before calling
917         * {@link #extractCollectionObjects(String, Repository, Class, Field, String, String)}
918         * to actually get the objects.
919         *
920         * @param field
921         *            The field which is the collection
922         * @param objectToUnserialize
923         *            The object in which the field exists
924         * @param objectRootURI
925         *            The URI of the object in which the field exists
926         * @param repo
927         *            The repository containing the RDF graph
928         * @param predicateURI
929         *            The name of the predicate for the collection items.
930         */
931        private void unserializeCollection(final Field field,
932                        final Object objectToUnserialize, final String objectRootURI,
933                        final Repository repo, final URIImpl predicateURI)
934        {
935                // If we have a collection object, then we can do something
936                // a bit different here. We know it's a collection, so we
937                // simply iterate through the sequence getting each item in
938                // turn and deserialize it.
939                if (Collection.class.isAssignableFrom(field.getType())) {
940                        try {
941                                // We get the class from the object that we're populating
942                                Class<?> cls = field.getType();
943
944                                // Attempt to instantiate the new object.
945                                // This may fail if the object does not have a
946                                // default or accessible constructor. In which case
947                                // we'll ignore the object here.
948                                Object newInstance;
949                                try {
950                                        newInstance = cls.newInstance();
951                                } catch (final InstantiationException e) {
952                                        cls = (Class<?>) this.getObjectClass(
953                                                        objectRootURI + "_" + field.getName(), repo);
954
955                                        // If we can't get a class to instantiate,
956                                        // we cannot do anything. Probably the field was null.
957                                        if (cls == null)
958                                                return;
959
960                                        newInstance = cls.newInstance();
961                                }
962
963                                // Cast to a collection
964                                @SuppressWarnings("unchecked")
965                                final Collection<Object> collection = (Collection<Object>) newInstance;
966
967                                // We must clear the collection here. We will populate
968                                // it will everything that was in it when it was created,
969                                // and if the constructor adds stuff to the collection,
970                                // this will end up with a collection that is not the same
971                                // as the original.
972                                collection.clear();
973
974                                // Get the collection of the type
975                                Class<?> collectionType = null;
976                                collectionType = ResolvableType.forField(field).asCollection().resolveGeneric();
977
978                                // Now unserialise the collection.
979                                final Object[] seq = this.extractCollectionObjects(
980                                                objectRootURI, repo, collectionType,
981                                                field.getName(), objectRootURI, predicateURI.stringValue());
982
983                                // If we have some stuff, then put it into the field.
984                                if (seq != null) {
985                                        // Add all the extracted objects into the collection
986                                        for (int i = 0; i < seq.length; i++)
987                                                collection.add(seq[i]);
988
989                                        // Set the field value to the new collection
990                                        field.setAccessible(true);
991                                        field.set(objectToUnserialize, collection);
992                                }
993                        } catch (final SecurityException e) {
994                                e.printStackTrace();
995                        } catch (final IllegalArgumentException e) {
996                                e.printStackTrace();
997                        } catch (final InstantiationException e1) {
998                                e1.printStackTrace();
999                        } catch (final IllegalAccessException e) {
1000                                e.printStackTrace();
1001                        }
1002                } else {
1003                        System.out.println("WARNING: Unserialize collection called for" +
1004                                        " something that's not a collection.");
1005                }
1006        }
1007
1008        /**
1009         * Returns an object extracted from the OpenRDF {@link Value} for this field. If
1010         * it's a primitive type, the object will be that primitive type. Otherwise, the
1011         * object will be deserialised and its reference passed back.
1012         *
1013         * @param type
1014         *            The type of the field
1015         * @param value
1016         *            The RDF value object for the field.
1017         * @param repo
1018         *            The RDF Graph repository in use.
1019         * @param fieldName
1020         *            The field name
1021         * @param subjectURI
1022         *            The URI of the object
1023         * @return The deserialised object.
1024         */
1025        private Object getFieldValue(final Type type, final Value value,
1026                        final Repository repo, final String fieldName,
1027                        final String subjectURI)
1028        {
1029                try {
1030                        // ---- String value ----
1031                        if (type.equals(String.class)) {
1032                                return value.stringValue();
1033                        }
1034                        // ---- URI or URL values ----
1035                        else if (type.equals(java.net.URI.class)) {
1036                                try {
1037                                        return new java.net.URI(value.toString());
1038                                } catch (final URISyntaxException e) {
1039                                        e.printStackTrace();
1040                                }
1041                        }
1042                        // ---- URI or URL values ----
1043                        else if (type.equals(URL.class)) {
1044                                try {
1045                                        return new URL(value.toString());
1046                                } catch (final MalformedURLException e) {
1047                                        e.printStackTrace();
1048                                }
1049                        }
1050                        // ---- Integer values ----
1051                        else if (type.equals(Integer.class)
1052                                        || type.equals(int.class))
1053                        {
1054                                return Integer.parseInt(value.stringValue());
1055                        }
1056                        // ---- Double values ----
1057                        else if (type.equals(Double.class)
1058                                        || type.equals(double.class))
1059                        {
1060                                return Double.parseDouble(value.stringValue());
1061                        }
1062                        // ---- Float values ----
1063                        else if (type.equals(Float.class)
1064                                        || type.equals(float.class))
1065                        {
1066                                return Float.parseFloat(value.stringValue());
1067                        }
1068                        // ---- Other complex objects ----
1069                        else {
1070                                // The object is not a default type that we understand.
1071                                // So what we must do is try to instantiate the object,
1072                                // then attempt to deserialize that object, then set the field
1073                                // in this object.
1074                                try {
1075                                        if (value instanceof URI) {
1076                                                String objectURI = value.stringValue();
1077
1078                                                // Try and look up the className predicate of the
1079                                                // object.
1080                                                Type type2 = this.getObjectClass(objectURI, repo);
1081                                                if (type2 == null)
1082                                                        type2 = this.getObjectClass(objectURI = subjectURI
1083                                                                        + "_" + fieldName, repo);
1084
1085                                                // Attempt to instantiate the new object.
1086                                                // This may fail if the object does not have a
1087                                                // default or accessible constructor.
1088                                                final Object newInstance = ((Class<?>) type2)
1089                                                                .newInstance();
1090
1091                                                // Now recurse the unserialization down the object tree,
1092                                                // by attempting to unserialize the given object.
1093                                                return this.unserialize(newInstance, objectURI, repo);
1094                                        } else {
1095                                                System.out
1096                                                                .println("WARNING: I don't know what to do with "
1097                                                                                + value);
1098                                        }
1099                                } catch (final InstantiationException e) {
1100                                        e.printStackTrace();
1101                                }
1102                        }
1103                } catch (final IllegalArgumentException e) {
1104                        e.printStackTrace();
1105                } catch (final IllegalAccessException e) {
1106                        e.printStackTrace();
1107                }
1108
1109                return null;
1110        }
1111
1112        /**
1113         * Returns whether the collection given by collectionURI is an RDF sequence or
1114         * not. It does this by asking the SPARQL store whether the URI has the type
1115         * rdf:Seq.
1116         *
1117         * @param repo
1118         *            The repository containing the graph
1119         * @param collectionURI
1120         *            The URI of the collection to check
1121         * @return TRUE if the collection is of type rdf:Seq; FALSE otherwise or if an
1122         *         error occurs.
1123         */
1124        private boolean isRDFSequence(final Repository repo, final String collectionURI) {
1125                // Before we retrieve the objects from the sequence, we'll first
1126                // double check that it really is a sequence. If it's not (it's a
1127                // collection of unordered triples), then we'll treat it differently.
1128                try {
1129                        final RepositoryConnection c = repo.getConnection();
1130                        final String queryString = "ASK {<" + collectionURI + "> <"
1131                                        + RDF.TYPE + "> <" + RDF.SEQ + ">}";
1132                        final BooleanQuery query = c.prepareBooleanQuery(
1133                                        QueryLanguage.SPARQL, queryString);
1134                        return query.evaluate();
1135                } catch (final RepositoryException e1) {
1136                        e1.printStackTrace();
1137                } catch (final MalformedQueryException e1) {
1138                        e1.printStackTrace();
1139                } catch (final QueryEvaluationException e1) {
1140                        e1.printStackTrace();
1141                }
1142
1143                return false;
1144        }
1145
1146        /**
1147         * Returns a list of objects that have been deserialised from an unordered
1148         * collection or an rdf:Seq in the graph. A test is made to determine which type
1149         * the collection is, and it will be dealt with in the appropriate way. The
1150         * method, if it succeeds, always returns an array of objects.
1151         *
1152         * @param collectionURI
1153         *            The URI of the collection from which to get items
1154         * @param repo
1155         *            The repository containing the RDF graph
1156         * @param componentType
1157         *            The Java type of each component in the graph
1158         * @param field
1159         *            The collection field to be set
1160         * @param subject
1161         *            The URI of the object in which the collection is a member
1162         * @param predicate
1163         *            The predicate that maps the collection to the object
1164         * @return An array of deserialised objects
1165         */
1166        @SuppressWarnings("unchecked")
1167        private <T> T[] extractCollectionObjects(final String collectionURI,
1168                        final Repository repo, final Class<T> componentType,
1169                        final String fieldName, final String subject, final String predicate)
1170        {
1171                // This will be the output of the method - an array of
1172                // all the objects in order. May contain nulls.
1173                T[] sequence = null;
1174
1175                // Check whether the collection is a sequence. If it is, then we
1176                // can get the collection of objects and put them into an appropriate
1177                // array
1178                if (this.isRDFSequence(repo, collectionURI)) {
1179                        // We'll get all the results into this map to start with.
1180                        // It maps an index (in the sequence) to the binding set from the query
1181                        final HashMap<Integer, BindingSet> tmpMap = new HashMap<Integer, BindingSet>();
1182
1183                        try {
1184                                // Extract the objects from the RDF sequence
1185                                final int max = this.extractRDFSequenceObjects(
1186                                                collectionURI, repo, tmpMap);
1187
1188                                // If there was no sequence object, we'll return
1189                                if (max < 0)
1190                                        return null;
1191
1192                                // So we've processed and stored all the results. Now we need to
1193                                // make sure our output array is big enough for all the results.
1194                                sequence = (T[]) Array.newInstance(componentType, max);
1195
1196                                // Now loop through all the values and poke them into the array.
1197                                // Note that we convert the indices to 0-based (RDF.Seq are
1198                                // 1-based indices).
1199                                for (final int i : tmpMap.keySet())
1200                                        sequence[i - 1] = (T) this.getFieldValue(
1201                                                        componentType,
1202                                                        tmpMap.get(i).getValue("o"),
1203                                                        repo, fieldName,
1204                                                        collectionURI);
1205                        } catch (final RepositoryException e) {
1206                                e.printStackTrace();
1207                        } catch (final MalformedQueryException e) {
1208                                e.printStackTrace();
1209                        } catch (final QueryEvaluationException e) {
1210                                e.printStackTrace();
1211                        }
1212                } else {
1213                        sequence = this.getUnorderedObjects(
1214                                        collectionURI, repo, componentType,
1215                                        fieldName, subject, predicate);
1216                }
1217
1218                return sequence;
1219        }
1220
1221        /**
1222         * Extracts a set of objects from an RDF sequence and returns a map containing
1223         * the objects mapped to their index.
1224         *
1225         * @param collectionURI
1226         *            The URI of the collection to extract
1227         * @param repo
1228         *            The repository containing the RDF graph
1229         * @param objectMap
1230         *            The map of the sequence objects
1231         * @return The maximum index of a sequence object extracted
1232         * @throws RepositoryException
1233         * @throws MalformedQueryException
1234         * @throws QueryEvaluationException
1235         */
1236        private int extractRDFSequenceObjects(final String collectionURI,
1237                        final Repository repo, final HashMap<Integer, BindingSet> objectMap)
1238                        throws RepositoryException, MalformedQueryException,
1239                        QueryEvaluationException
1240        {
1241                int max = -1;
1242
1243                // First we select all the links from the collectionURI
1244                // out using the SPARQL query:
1245                // SELECT <collectionURI> ?p ?o
1246                // ordered by the predicate name, as we're expecting those
1247                // to be rdf:_1, rdf:_2, etc. etc.
1248                final RepositoryConnection c = repo.getConnection();
1249                final String queryString = "SELECT ?p ?o WHERE {<" + collectionURI
1250                                + "> ?p ?o} ORDER BY DESC(?p)";
1251                final TupleQuery tupleQuery = c.prepareTupleQuery(
1252                                QueryLanguage.SPARQL, queryString);
1253
1254                // This actually does the query to the store...
1255                final TupleQueryResult result = tupleQuery.evaluate();
1256
1257                // Loop through the results...
1258                while (result.hasNext()) {
1259                        try {
1260                                final BindingSet bs = result.next();
1261
1262                                // If the predicate is a sequence number (starts with rdf:_)
1263                                // then we parse the integer into the index variable.
1264                                // If it's not a NumberFormatException is thrown
1265                                // (and caught and ignored because it's clearly not an
1266                                // RDF sequence URI)
1267                                final int index = Integer.parseInt(
1268                                                bs.getValue("p").stringValue()
1269                                                                .substring("http://www.w3.org/1999/02/22-rdf-syntax-ns#_"
1270                                                                                .length()));
1271
1272                                // Just be sure we're doing something sensible.
1273                                if (index >= 0) {
1274                                        // Stick it in the map.
1275                                        objectMap.put(index, bs);
1276
1277                                        // Store the maximum index
1278                                        max = Math.max(index, max);
1279                                }
1280                        } catch (final NumberFormatException e) {
1281                                // If we get a NFE then it's probably not a sequence number.
1282                        } catch (final StringIndexOutOfBoundsException e) {
1283                                // If we get a SOOBE then it's probably because the
1284                                // predicate
1285                                // is not a sequence number.
1286                        }
1287                }
1288                return max;
1289        }
1290
1291        /**
1292         * Returns a list of unserialised objects that were unserialised from an
1293         * unordered list of triples in RDF
1294         *
1295         * @param sequenceURI
1296         *            The URI of the triples
1297         * @param repo
1298         *            The repository
1299         * @param fieldType
1300         *            The field type
1301         * @param field
1302         *            The field
1303         * @return An array of objects, in an arbitrary order.
1304         */
1305        @SuppressWarnings("unchecked")
1306        private <T> T[] getUnorderedObjects(final String sequenceURI,
1307                        final Repository repo, final Class<T> fieldType,
1308                        final String fieldName,
1309                        final String subjectURI, final String predicate)
1310        {
1311                try {
1312                        // First select all the objects that link the main object
1313                        // with the collection objects via the collection predicate.
1314                        // We use the SPARQL query:
1315                        // SELECT ?o WHERE { <subjectURI> <predicate> ?o . }
1316                        // The results are in any order.
1317                        final RepositoryConnection c = repo.getConnection();
1318                        final String queryString = "SELECT ?o WHERE {<" + subjectURI
1319                                        + "> <" + predicate + "> ?o}";
1320                        final TupleQuery tupleQuery = c.prepareTupleQuery(
1321                                        QueryLanguage.SPARQL, queryString);
1322
1323                        // Evaluate the query, to get the results.
1324                        final TupleQueryResult result = tupleQuery.evaluate();
1325
1326                        // We'll aggregate all the objects into this general list.
1327                        final ArrayList<T> objs = new ArrayList<T>();
1328                        int n = 0;
1329                        while (result.hasNext()) {
1330                                final BindingSet bs = result.next();
1331                                final Value oo = bs.getBinding("o").getValue();
1332
1333                                // Get the value of the field if it's a primitive, or
1334                                // it's URI if it's a complex object and add it to
1335                                // the list.
1336                                objs.add((T) this.getFieldValue(fieldType,
1337                                                oo, repo, fieldName, sequenceURI));
1338                                n++;
1339                        }
1340
1341                        // Copy the values into an array
1342                        final T[] arr = (T[]) Array.newInstance(fieldType, n);
1343                        for (int i = 0; i < arr.length; i++)
1344                                arr[i] = objs.get(i);
1345
1346                        return arr;
1347                } catch (final RepositoryException e) {
1348                        e.printStackTrace();
1349                } catch (final MalformedQueryException e) {
1350                        e.printStackTrace();
1351                } catch (final QueryEvaluationException e) {
1352                        e.printStackTrace();
1353                }
1354
1355                return null;
1356        }
1357
1358        /**
1359         * Attempts to find the correct class for the object URI given. If a class name
1360         * cannot be found in the repository, then the field is used to attempt to
1361         * instantiate a class.
1362         *
1363         * @param objectURI
1364         *            The URI of the object in the repo
1365         * @param repo
1366         *            The RDF repository
1367         * @return A class object.
1368         */
1369        private Type getObjectClass(final String objectURI, final Repository repo) {
1370                String queryString = null;
1371                try {
1372                        final RepositoryConnection c = repo.getConnection();
1373
1374                        queryString = "SELECT ?o WHERE {<" + objectURI + "> <"
1375                                        + RDFSerializer.RDF_OPENIMAJ_P_CLASSNAME + "> ?o.}";
1376                        final TupleQuery tupleQuery = c.prepareTupleQuery(
1377                                        QueryLanguage.SPARQL, queryString);
1378                        final TupleQueryResult result = tupleQuery.evaluate();
1379
1380                        // System.out.println( queryString );
1381
1382                        // We'll look at all the results until we find a class we can
1383                        // instantiate. Of course, we expect there to be only one in
1384                        // reality.
1385                        Class<?> clazz = null;
1386                        boolean found = false;
1387                        while (!found && result.hasNext()) {
1388                                final Value value = result.next().getValue("o");
1389
1390                                try {
1391                                        // Try to find the class with the given name
1392                                        clazz = Class.forName(value.stringValue());
1393
1394                                        // If the above succeeds, then we are done
1395                                        found = true;
1396                                } catch (final ClassNotFoundException e) {
1397                                        e.printStackTrace();
1398                                }
1399                        }
1400
1401                        // Close the repo connection.
1402                        c.close();
1403
1404                        // Return the class if we have one.
1405                        if (clazz != null) {
1406                                // System.out.println( clazz );
1407                                return clazz;
1408                        }
1409
1410                } catch (final RepositoryException e) {
1411                        System.out.println("Processing: " + queryString);
1412                        e.printStackTrace();
1413                } catch (final MalformedQueryException e) {
1414                        System.out.println("Processing: " + queryString);
1415                        e.printStackTrace();
1416                } catch (final QueryEvaluationException e) {
1417                        System.out.println("Processing: " + queryString);
1418                        e.printStackTrace();
1419                }
1420
1421                // Can't determine a class from the repository? Then we'll fall back
1422                // to the field's type.
1423                return null;
1424        }
1425
1426        /**
1427         * Returns a URI for the given object. If it cannot determine one, it will
1428         * return the default URI. It attempts to determine the object's URI by looking
1429         * for a getURI() method in the object. If it has one, it invokes it and uses
1430         * the return value as the object's URI, otherwise it will use the default URI
1431         * passed in via the method parameters.
1432         *
1433         * @param obj
1434         *            The object
1435         * @param defaultURI
1436         *            A default value for the URI
1437         * @return A URI for the object
1438         */
1439        public URIImpl getObjectURI(final Object obj, final URIImpl defaultURI) {
1440                // Check whether the object has a getURI() method. If so, then
1441                // what we'll do is this: we'll call the getURI() method to retrieve the
1442                // URI of the object and use that as the subject URI instead of the
1443                // uri that's passed in via the method parameters.
1444                try {
1445                        final Method method = obj.getClass().getMethod("getURI");
1446
1447                        // We'll call the method and use the toString() method to
1448                        // get the URI as a string. We'll instantiate a new URIImpl with it.
1449                        final URIImpl subject = new URIImpl(method.invoke(obj,
1450                                        (Object[]) null).toString());
1451
1452                        return subject;
1453                } catch (final NoSuchMethodException e1) {
1454                } catch (final SecurityException e1) {
1455                        e1.printStackTrace();
1456                } catch (final IllegalAccessException e) {
1457                        e.printStackTrace();
1458                } catch (final IllegalArgumentException e) {
1459                        e.printStackTrace();
1460                } catch (final InvocationTargetException e) {
1461                        e.printStackTrace();
1462                }
1463
1464                return defaultURI;
1465        }
1466
1467        /**
1468         * Checks whether the field value is a special field. If so, it will output it
1469         * using a separate device than the main serialization loop. Otherwise the
1470         * method returns FALSE and the main loop continues.
1471         * <p>
1472         * A special field is one which has some annotation that requires the output be
1473         * performed in a separate way. One example of this is the {@link TripleList}
1474         * annotation which forces the outputs of triples directly from the value of the
1475         * object. Similarly for the {@link RelationList} which forces the output of
1476         * triples from the pairs stored in the object's value.
1477         *
1478         * @param fieldValue
1479         *            the value of the field
1480         * @param field
1481         *            The field definition
1482         * @return
1483         */
1484        private boolean outputSpecial(final Object fieldValue, final Field field,
1485                        final URIImpl subjectURI)
1486        {
1487                // Check whether this field is a triple list. If it is, we'll take
1488                // the triples from the field (assuming it's the right type) and
1489                // bang them into the triple store.
1490                if (field.getAnnotation(TripleList.class) != null) {
1491                        if (fieldValue instanceof Collection) {
1492                                for (final Object o : (Collection<?>) fieldValue) {
1493                                        if (o instanceof Statement)
1494                                                this.addTriple((Statement) o);
1495                                }
1496                        }
1497                        return true; // stop the main loop processing this field
1498                } else
1499                // If the field is a relation list, process each in turn
1500                if (field.getAnnotation(RelationList.class) != null) {
1501                        if (fieldValue instanceof Collection) {
1502                                int count = 0;
1503                                for (final Object o : (Collection<?>) fieldValue) {
1504                                        if (o instanceof IndependentPair<?, ?>) {
1505                                                final IndependentPair<?, ?> ip = (IndependentPair<?, ?>) o;
1506
1507                                                Value ooo;
1508                                                if ((ooo = this.checkPrimitive(ip.getSecondObject())) != null)
1509                                                        this.addTriple(new StatementImpl(
1510                                                                        subjectURI,
1511                                                                        new URIImpl(ip.getFirstObject().toString()),
1512                                                                        ooo));
1513                                                else {
1514                                                        final URI subjU = this.serializeAux(
1515                                                                        ip.getSecondObject(), subjectURI + "_"
1516                                                                                        + field.getName() + "_" + count++);
1517                                                        this.addTriple(new StatementImpl(
1518                                                                        subjectURI,
1519                                                                        new URIImpl(ip.getFirstObject().toString()),
1520                                                                        subjU));
1521                                                }
1522                                        } else
1523                                                this.serializeAux(o,
1524                                                                subjectURI + "_" + field.getName() + "_"
1525                                                                                + count++);
1526                                }
1527                        }
1528                        return true; // stop the main loop processing this field
1529                }
1530
1531                return false; // continue on the main loop
1532        }
1533
1534        /**
1535         * Adds a single triple to some RDF serializer.
1536         *
1537         * @param t
1538         *            The triple to add
1539         */
1540        public void addTriple(final Statement t) {
1541                // Default implementation does nothing. Subclasses should override
1542                // this method and do something useful with created triples.
1543                // This method is not abstract just so users can create this object
1544                // for unserialization.
1545        }
1546}