diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index 1657563..4caaa76 100755
--- a/README.md
+++ b/README.md
@@ -1 +1,159 @@
-# Java API for Thing Descriptions of WoT (JDT)
\ No newline at end of file
+# Java API for Thing Descriptions of WoT (JDTs)
+[![Maven Central](https://img.shields.io/badge/Maven%20Central-v0.1.6-orange)](https://search.maven.org/search?q=g:%22es.upm.fi.oeg%22%20AND%20a:%22wot-jtd%22) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GitHub stars](https://img.shields.io/github/stars/Naereen/StrapDown.js.svg?style=social&label=Star&maxAge=2592000)](https://github.com/oeg-upm/wot-jtd/stargazers)
+
+The JDT is an ORM implementation of the current [Thing Description](https://www.w3.org/TR/wot-thing-description/) model standardised by the [W3C Web of Things group](https://www.w3.org/WoT/). The current features are:
+ * Serialise:
+ * Serialise any Thing Description as a Java Object, i.e., a JDT
+ * Serialise a JDT from a JSON-LD framed document
+ * Serialise a JDT from a set of RDF triples
+ * Round trip-translation:
+ * Translate from a JSON-LD framed document into a set of equivalent RDF triples
+ * Translate a set of RDF triples into its equivalent JSON-LD framed document
+ * Validation **(coming soon)**
+ * Validate a JTD using [SHACL shapes](https://www.w3.org/TR/shacl/)
+ * Validate a JTD using [JSON schema](https://json-schema.org/)
+ * Validate a JTD according to the [restrictions specified in the standard](https://www.w3.org/TR/wot-thing-description/)
+
+If you have any feedback or feature suggestion, please let us know posting an issue with the label **feedback**
+
+## Table of contents
+
+* Installation
+* Model
+* Usage:
+ * Serialisation of JTDs:
+ * From JSON-LD framed document
+ * From RDF triples
+ * Deserialisation of JTDs:
+ * To JSON-LD framed
+ * To RDF triples
+ * JDT validation:
+ * Using SHACL shapes
+ * Using JSON schema (**coming soon**)
+ * Using restrictions in the model (**coming soon**)
+
+
+
+## Installation:
+Import the JDTs library as a maven dependency, **be sure to specify the latest version**:
+
+```
+
+ es.upm.fi.oeg
+ wot-jtd
+ 0.1.6
+
+```
+
+Alternatively, the dependency can be installed manually. First, download the latest jar from the [releases section](), and then install the dependency as follows (**be sure to specify the latest version**):
+````
+mvn install:install-file -Dfile=wot-jtd.jar -DgroupId=es.upm.fi.oeg -DartifactId=wot-jtd -Dversion=0.1.6 -Dpackaging=jar
+````
+
+Check our [Maven Central Repository page](https://search.maven.org/artifact/es.upm.fi.oeg/wot-jtd/0.1.6/jar) to discover other installation options like Gradle Groovy or Kotlin, Scala, and others.
+
+## Model
+
+The JDT library implement as Java objects the whole model, and its restrictions, defined in the [Thing Description standard](https://www.w3.org/TR/wot-thing-description/). The overview of the model is the following:
+
+![Thing Description model](https://www.w3.org/TR/wot-thing-description/visualization/td.png)
+
+
+## Usage
+
+### Serialisation of JTDs:
+
+For the next examples, let's assume the following java variables containing the same Thing description:
+````
+String strJsonTD = "{ \"@context\": \"https://www.w3.org/2019/wot/td/v1\",\n" +
+" \"id\": \"urn:dev:ops:32473-WoTLamp-1234\",\n" +
+" \"title\": \"MyLampThing\",\n" +
+" \"securityDefinitions\": { \"nosec_sc\": { \"scheme\": \"nosec\" }},\n" +
+" \"security\": \"nosec_sc\",\n" +
+" \"properties\": {\n" +
+" \"status\": {\n" +
+" \"type\": \"string\",\n" +
+" \"forms\": [{\"href\": \"https://mylamp.example.com/status\"}]\n" +
+" }\n" +
+" }\n" +
+"}";
+````
+
+````
+Model modelTD = ModelFactory.createDefaultModel();
+String strRdfTD = "@prefix dc: .\n" +
+"@prefix td: .\n" +
+"@prefix jsonschema: .\n" +
+"@prefix hctl: .\n" +
+"\n" +
+"\n" +
+" dc:title \"MyLampThing\" ;\n" +
+" td:hasPropertyAffordance [\n" +
+" a ;\n" +
+" jsonschema:propertyName \"status\" ;\n" +
+" td:hasForm [ hctl:hasTarget ]\n" +
+" ] ;\n" +
+" td:hasSecurityConfiguration ;\n" +
+" td:securityDefinitions [ td:scheme \"nosec\" ] .";
+
+##### Read the string variable into the jena model
+modelTD.read(new ByteArrayInputStream(strRdfTD.getBytes()), null, "Turtle");
+````
+
+
+
+The following serialisation operations consists of building a JTD object Thing from either a JSON-LD framed representation or a set of RDF triples.
+##### From JSON-LD framed document
+
+````
+JsonObject jsonTD = JTD.parseJson(strJsonTD);
+Thing thing = Thing.fromJson(jsonTD);
+thing = (Thing) JTD.instantiateFromJson(jsonTD, Thing.class); # Alternativelly
+````
+Notice that using the method `JTD.instantiateFromJson(jsonTD, Thing.class)` any other class from the model can be serialised.
+
+##### From RDF triples
+In order to build a JTD object from a set of RDF triples there are two main methods:
+##### A) Build a list of JTDs in case that the triples contain more than one Thing resource.
+`````
+List things = fromRDF(modelTD)
+`````
+##### B) Build a unique JTDs providing the RDF resource URI.
+`````
+Thing thing = fromRDF(modelTD, "urn:dev:ops:32473-WoTLamp-1234")
+`````
+
+### Deserialisation of JTDs:
+
+##### To JSON-LD framed
+````
+JsonObject jsonTD = thing.toJson()
+jsonTD = JTD.toJson(thing) # Alternativelly
+````
+Notice that using the method `JTD.toJson(thing)` any other class from the model can be deserialised.
+
+##### To RDF triples
+
+````
+Model modelTD = JTD.toRDF(thing)
+ # Alternativelly
+JsonObject jsonTD = thing.toJson()
+modelTD = JTD.toRDF(jsonTD)
+````
+
+Notice that using the method alternative `JTD.toRDF(jsonTD)` there is actually no need to serialise the JSON-LD framed `jsonTD` as a Java object, it can be directly translated into RDF.
+
+
+### JDT validation
+
+##### Using SHACL shapes
+Currently, the Web of Things provides [an official SHACL shape document](https://github.com/w3c/wot-thing-description/blob/main/validation/td-validation.ttl) for validating Thing Descriptions. This shape, or any other, can be used to validate a JTD Thing as follows:
+
+````
+String shapesURI = "https://raw.githubusercontent.com/w3c/wot-thing-description/main/validation/td-validation.ttl"
+Model shapesGraph = RDFDataMgr.loadModel(shapesURI, Lang.TURTLE);
+ValidationReport shapeReport = JTD.validateWithShape(thing, shapesGraph);
+````
+
+##### Using JSON schema (*comming soon*)
+##### Using restrictions in the model (*comming soon*)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 500d633..4ce5afd 100755
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0es.upm.fi.oegwot-jtd
- 0.1.8
+ 0.2.0https://oeg-upm.github.io/wot-jtdJava Thing Description APIThis API aims at assisting developers for handling WoT Thing Descriptions, providing special support for RDF.
@@ -48,6 +48,13 @@
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
@@ -157,6 +164,8 @@
hibernate-validator6.0.13.Final
+
+
org.glassfishjavax.el
@@ -193,18 +202,14 @@
commons-lang33.11
-
-
-
- com.apicatalog
- titanium-json-ld
- 1.0.0
+
+
+
+ com.github.everit-org.json-schema
+ org.everit.json.schema
+ 1.12.2
-
- org.glassfish
- jakarta.json
- 2.0.0
-
+
@@ -214,6 +219,8 @@
pom
+
+
junit
@@ -222,6 +229,7 @@
test
+
diff --git a/src/main/java/kehio/annotations/RdfContainer.java b/src/main/java/kehio/annotations/RdfContainer.java
index 7f71f46..16744c0 100644
--- a/src/main/java/kehio/annotations/RdfContainer.java
+++ b/src/main/java/kehio/annotations/RdfContainer.java
@@ -10,5 +10,8 @@
@Target(ElementType.FIELD)
@Inherited
public @interface RdfContainer {
-
+ String[] ignore() default {};
+ RdfUrlMap[] prefixes() default {};
+ RdfUrlMap[] aliases(); // if property is present in alias, overrides the ignore properties
+ String[] identifiers();
}
diff --git a/src/main/java/kehio/annotations/done/RdfDatatype.java b/src/main/java/kehio/annotations/RdfDatatype.java
similarity index 87%
rename from src/main/java/kehio/annotations/done/RdfDatatype.java
rename to src/main/java/kehio/annotations/RdfDatatype.java
index 3a75a45..fc3e34e 100644
--- a/src/main/java/kehio/annotations/done/RdfDatatype.java
+++ b/src/main/java/kehio/annotations/RdfDatatype.java
@@ -1,4 +1,4 @@
-package kehio.annotations.done;
+package kehio.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -15,8 +15,5 @@
String datatype() default "";
boolean sinkLang() default false;
boolean sinkDatatype() default false;
- boolean isPath() default false;
-
-
}
diff --git a/src/main/java/kehio/annotations/done/RdfDatatypeContainer.java b/src/main/java/kehio/annotations/RdfDatatypeGroup.java
similarity index 78%
rename from src/main/java/kehio/annotations/done/RdfDatatypeContainer.java
rename to src/main/java/kehio/annotations/RdfDatatypeGroup.java
index 6a8bc06..7a2af68 100644
--- a/src/main/java/kehio/annotations/done/RdfDatatypeContainer.java
+++ b/src/main/java/kehio/annotations/RdfDatatypeGroup.java
@@ -1,4 +1,4 @@
-package kehio.annotations.done;
+package kehio.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -9,9 +9,8 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Inherited
-public @interface RdfDatatypeContainer {
+public @interface RdfDatatypeGroup {
String value() default "";
boolean byLang() default false;
boolean byDatatype() default false;
- boolean isPath() default false;
}
diff --git a/src/main/java/kehio/annotations/done/RdfId.java b/src/main/java/kehio/annotations/RdfId.java
similarity index 91%
rename from src/main/java/kehio/annotations/done/RdfId.java
rename to src/main/java/kehio/annotations/RdfId.java
index c39d30d..f51948e 100644
--- a/src/main/java/kehio/annotations/done/RdfId.java
+++ b/src/main/java/kehio/annotations/RdfId.java
@@ -1,4 +1,4 @@
-package kehio.annotations.done;
+package kehio.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
diff --git a/src/main/java/kehio/annotations/done/RdfObject.java b/src/main/java/kehio/annotations/RdfObject.java
similarity index 68%
rename from src/main/java/kehio/annotations/done/RdfObject.java
rename to src/main/java/kehio/annotations/RdfObject.java
index 730e5d9..8793fd4 100644
--- a/src/main/java/kehio/annotations/done/RdfObject.java
+++ b/src/main/java/kehio/annotations/RdfObject.java
@@ -1,4 +1,4 @@
-package kehio.annotations.done;
+package kehio.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -11,5 +11,7 @@
@Inherited
public @interface RdfObject {
String value() default "";
- boolean isPath() default false;
+ String base() default "";
+ RdfUrlMap[] aliases() default {};
+ boolean strict() default false; // if true only matches aliases
}
diff --git a/src/main/java/kehio/annotations/done/RdfObjectContainer.java b/src/main/java/kehio/annotations/RdfObjectGroup.java
similarity index 71%
rename from src/main/java/kehio/annotations/done/RdfObjectContainer.java
rename to src/main/java/kehio/annotations/RdfObjectGroup.java
index 060337b..6f09932 100644
--- a/src/main/java/kehio/annotations/done/RdfObjectContainer.java
+++ b/src/main/java/kehio/annotations/RdfObjectGroup.java
@@ -1,4 +1,4 @@
-package kehio.annotations.done;
+package kehio.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -9,8 +9,10 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Inherited
-public @interface RdfObjectContainer {
+public @interface RdfObjectGroup {
String value() default "";
String key() default "";
- boolean isPath() default false;
+ boolean includeKey() default true;
+ RdfUrlMap[] aliases() default {};
+
}
diff --git a/src/main/java/kehio/annotations/RdfPrefix.java b/src/main/java/kehio/annotations/RdfPrefix.java
deleted file mode 100644
index 646b851..0000000
--- a/src/main/java/kehio/annotations/RdfPrefix.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package kehio.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Inherited
-public @interface RdfPrefix {
- String prefix() default "";
- String value() default "";
-}
-
diff --git a/src/main/java/kehio/annotations/RdfNameSpace.java b/src/main/java/kehio/annotations/RdfPropertiesContainer.java
similarity index 60%
rename from src/main/java/kehio/annotations/RdfNameSpace.java
rename to src/main/java/kehio/annotations/RdfPropertiesContainer.java
index d479879..3345895 100644
--- a/src/main/java/kehio/annotations/RdfNameSpace.java
+++ b/src/main/java/kehio/annotations/RdfPropertiesContainer.java
@@ -7,9 +7,10 @@
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
+@Target(ElementType.FIELD)
@Inherited
-public @interface RdfNameSpace {
- RdfPrefix[] prefix() default {};
+public @interface RdfPropertiesContainer {
+ //boolean onlyDatatypes() default false;
+ String[] ignore() default {};
+ RdfUrlMap[] prefixes() default {};
}
-
diff --git a/src/main/java/kehio/annotations/RdfStaticType.java b/src/main/java/kehio/annotations/RdfUrlMap.java
similarity index 78%
rename from src/main/java/kehio/annotations/RdfStaticType.java
rename to src/main/java/kehio/annotations/RdfUrlMap.java
index 876473c..25d1322 100644
--- a/src/main/java/kehio/annotations/RdfStaticType.java
+++ b/src/main/java/kehio/annotations/RdfUrlMap.java
@@ -7,9 +7,9 @@
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
+@Target(ElementType.FIELD)
@Inherited
-public @interface RdfStaticType {
+public @interface RdfUrlMap {
String value() default "";
+ String key() default "";
}
-
diff --git a/src/main/java/kehio/annotations/done/RdfDatatypeCollection.java b/src/main/java/kehio/annotations/done/RdfDatatypeCollection.java
deleted file mode 100644
index 3e713df..0000000
--- a/src/main/java/kehio/annotations/done/RdfDatatypeCollection.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package kehio.annotations.done;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-@Inherited
-public @interface RdfDatatypeCollection {
- String value() default "";
- String lang() default "";
- String datatype() default "";
- boolean sinkLang() default false;
- boolean sinkDatatype() default false;
- boolean isPath() default false;
-}
-
diff --git a/src/main/java/kehio/annotations/done/RdfObjectCollection.java b/src/main/java/kehio/annotations/done/RdfObjectCollection.java
deleted file mode 100644
index ed9d88f..0000000
--- a/src/main/java/kehio/annotations/done/RdfObjectCollection.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package kehio.annotations.done;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-@Inherited
-public @interface RdfObjectCollection {
- String value() default "";
- boolean isPath() default false;
-}
diff --git a/src/main/java/kehio/mapper/Kehio.java b/src/main/java/kehio/mapper/Kehio.java
index e6260b9..cf599ac 100755
--- a/src/main/java/kehio/mapper/Kehio.java
+++ b/src/main/java/kehio/mapper/Kehio.java
@@ -1,17 +1,23 @@
package kehio.mapper;
+import java.io.ByteArrayInputStream;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.ResourceFactory;
import org.apache.jena.vocabulary.RDF;
@@ -24,28 +30,22 @@ public class Kehio {
// Order of inclusion in the list matters
mappers.add(new RdfIdMapper());
- mappers.add(new RdfDatatypeContainerSerialiser());
- mappers.add(new RdfDatatypeCollectionSerialiser());
+ mappers.add(new RdfDatatypeGroupMapper());
mappers.add(new RdfDatatypeMapper());
- mappers.add(new RdfObjectContainerSerialiser());
- mappers.add(new RdfObjectCollectionSerialiser());
- mappers.add(new RdfObjectSerialiser());
-
+ mappers.add(new RdfObjectGroupMapper());
+ mappers.add(new RdfObjectMapper());
}
-
-
-
- public static Object serializeClass(Class> clazz, Model model, Resource subject) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
+
+ public static Object serializeClass(Class> clazz, Model model, Resource subject) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, URISyntaxException {
Object object = null;
- Field[] fields = new Field[] {};
object = createInstance(clazz);
Class> clazzFull = Class.forName(clazz.getName());
// Retrieve fields from super-classes
- fields = extractFields(clazzFull);
+ Field[] fields = extractFields(clazzFull);
instantiateObject(object, fields, model, subject);
return object;
@@ -67,39 +67,72 @@ private static Field[] extractFields(Class extends Object> clazz) throws Class
return fields;
}
- private static void instantiateObject(Object object, Field[] fields, Model model, Resource subject) {
- //model.write(System.out,"TTL");
+ private static void instantiateObject(Object object, Field[] fields, Model model, Resource subject) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
if(object!=null) {
- Set processedProperties = new HashSet<>();
+ Set processedProperties = new HashSet<>();
for (int index=0; index < fields.length; index++) {
Field field = fields[index];
-
- String processedProperty = processSerialiseFieldAnnotation(field, object, model, subject);
-
- if(processedProperty==null || processedProperty.isEmpty())
- continue;
- if(processedProperty!=null && !processedProperty.isEmpty())
- processedProperties.add(processedProperty);
-
+ Set correctlyProcessedProperty = processSerialiseFieldAnnotation(field, object, model, subject);
+ if(correctlyProcessedProperty!=null)
+ processedProperties.addAll(correctlyProcessedProperty);
+ }
+ // add unknown RDF properties
+ enhanceObjectWithUnknownProperties(fields, processedProperties, object, model, subject);
+ // add unknown RDF triples
+ enhanceObjectWithUnknownTriples(fields, processedProperties, object, model, subject);
+ }
+ }
+
+ private static void enhanceObjectWithUnknownProperties(Field[] fields, Set processedProperties, Object object, Model model, Resource subject) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
+ RdfPropertiesContainerMapper mapperContainer = new RdfPropertiesContainerMapper();
+ mapperContainer.setPropertiesNotToContain(processedProperties);
+ int unknownAnnotations = 0;
+ for (int index=0; index < fields.length; index++) {
+ Field field = fields[index];
+ if(mapperContainer.hasProcesableAnnotation(field)) {
+ if(unknownAnnotations == 0)
+ mapperContainer.fromRdfToObject(field, object, model, subject);
+ unknownAnnotations++;
+ }else if(unknownAnnotations > 1) {
+ throw new IllegalArgumentException("A Java class can be annotated only with one Container notation");
}
}
}
- private static String processSerialiseFieldAnnotation(Field field, Object object, Model model, Resource subject) {
- String annotationApplied = "";
+ private static void enhanceObjectWithUnknownTriples(Field[] fields, Set processedProperties, Object object, Model model, Resource subject) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
+ RdfContainerMapper mapperContainer = new RdfContainerMapper();
+ mapperContainer.setPropertiesNotToContain(processedProperties);
+ int unknownAnnotations = 0;
+ for (int index=0; index < fields.length; index++) {
+ Field field = fields[index];
+ if(mapperContainer.hasProcesableAnnotation(field)) {
+ if(unknownAnnotations == 0)
+ mapperContainer.fromRdfToObject(field, object, model, subject);
+ unknownAnnotations++;
+ }else if(unknownAnnotations > 1) {
+ throw new IllegalArgumentException("A Java class can be annotated only with one Container notation");
+ }
+ }
+ }
+
+ private static Set processSerialiseFieldAnnotation(Field field, Object object, Model model, Resource subject) {
+ Set properties = null;
try {
for (int index=0; index < mappers.size(); index++) {
RdfMapper serialiser = mappers.get(index);
if(serialiser.hasProcesableAnnotation(field)) {
- annotationApplied = serialiser.fromRdfToObject(field, object, model, subject);
+ Property property = serialiser.fromRdfToObject(field, object, model, subject);
+
+ properties = new HashSet<>();
+ if(property!=null)
+ properties.add(property);
break;
}
}
}catch(Exception e) {
- System.out.println(field);
- System.out.println(e.toString());
+ throw new IllegalArgumentException(e.toString());
}
- return annotationApplied;
+ return properties;
}
private static Object createInstance(Class> clazz) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
@@ -112,39 +145,57 @@ private static Object createInstance(Class> clazz) throws InstantiationExcepti
public static Model deserializeClass(Object object) throws IllegalArgumentException, IllegalAccessException, URISyntaxException, ClassNotFoundException {
- Field[] fields = new Field[] {};
- Model model = ModelFactory.createDefaultModel();
+ return deserializeClassExtended(object).getValue();
+ }
+
+ public static Model deserializeClass(Object object, Map prefixes) throws IllegalArgumentException, IllegalAccessException, URISyntaxException, ClassNotFoundException {
+ return deserializeClassExtended(object, prefixes).getValue();
+ }
+ protected static Entry deserializeClassExtended(Object object) throws IllegalArgumentException, IllegalAccessException, URISyntaxException, ClassNotFoundException {
+ return deserializeClassExtended(object, null);
+ }
+
+ protected static Entry deserializeClassExtended(Object object, Map prefixes) throws IllegalArgumentException, IllegalAccessException, URISyntaxException, ClassNotFoundException {
+ Model model = ModelFactory.createDefaultModel();
+ if(prefixes!=null && !prefixes.isEmpty())
+ model.setNsPrefixes(prefixes);
+
Class> clazzFull = object.getClass();
// Retrieve fields from super-classes
- fields = extractFields(clazzFull);
- instantiateModel(object, fields, model);
+ Field[] fields = extractFields(clazzFull);
+ Resource subject = instantiateModel(object, fields, model);
- return model;
+ return Map.entry(subject, model);
}
-
- private static void instantiateModel(Object object, Field[] fields, Model model) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
-
+ private static Resource instantiateModel(Object object, Field[] fields, Model model) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
+ Resource subject = null;
if(object!=null) {
- Resource subject = findSubjectResource(fields,object, model);
+ subject = findSubjectResource(fields,object, model);
model.remove(subject, RDF.type, Kehio.KEHIO_TYPE);
for (int index=0; index < fields.length; index++) {
Field field = fields[index];
- processDeserialiseFieldAnnotation(field, object, model, subject);
+ field.setAccessible(true);
+ Object instantiatedField = field.get(object);
+ if(instantiatedField!=null)
+ processDeserialiseFieldAnnotation(field, object, model, subject);
}
}
+ return subject;
}
private static void processDeserialiseFieldAnnotation(Field field, Object object, Model model, Resource subject) throws IllegalArgumentException, IllegalAccessException, URISyntaxException {
-
- for (int index=0; index < mappers.size(); index++) {
- RdfMapper mapper = mappers.get(index);
+ List mappersAux = new ArrayList<>(mappers);
+ mappersAux.add(new RdfPropertiesContainerMapper());
+ mappersAux.add(new RdfContainerMapper());
+ for (int index=0; index < mappersAux.size(); index++) {
+ RdfMapper mapper = mappersAux.get(index);
if(!(mapper instanceof RdfIdMapper) && mapper.hasProcesableAnnotation(field)) {
- mapper.fromObjectToRdf(field, object, model, subject);
+ mapper.fromObjectToRdf(field, object, model, subject);
break;
}
diff --git a/src/main/java/kehio/mapper/KehioUtils.java b/src/main/java/kehio/mapper/KehioUtils.java
index 7c6a4ce..ca9ddfb 100644
--- a/src/main/java/kehio/mapper/KehioUtils.java
+++ b/src/main/java/kehio/mapper/KehioUtils.java
@@ -1,13 +1,28 @@
package kehio.mapper;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URI;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryExecutionFactory;
import org.apache.jena.query.QueryFactory;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.ResourceFactory;
@@ -24,8 +39,18 @@ private KehioUtils() {
}
+ // -- General methods
- protected static List retrieveFromRdfPath(Model model, Resource subject, String propertyPath, Boolean isPath) throws IllegalArgumentException, IllegalAccessException {
+ protected static String concatStrings(String ...message) {
+ StringBuilder builder = new StringBuilder();
+ for(int index =0; index < message.length; index++)
+ builder.append(message[index]);
+ return builder.toString();
+ }
+
+ // -- Data retrieval in RDF methods
+
+ /*protected static List retrieveFromRdfPath(Model model, Resource subject, String propertyPath, Boolean isPath) throws IllegalArgumentException, IllegalAccessException {
List range = null;
if(isPath) {
range = extractPathData( model, subject, propertyPath);
@@ -33,9 +58,15 @@ protected static List retrieveFromRdfPath(Model model, Resource subject
range = model.listObjectsOfProperty(subject, ResourceFactory.createProperty(propertyPath)).toList();
}
return range;
- }
+ }*/
+ protected static List objectNodes(Model model, Resource subject, Property property){
+ return model.listObjectsOfProperty(subject, property).toList();
+ }
+ protected static List objectNodes(Model model, Resource subject, String property){
+ return model.listObjectsOfProperty(subject, ResourceFactory.createProperty(property)).toList();
+ }
private static List extractPathData(Model model, Resource subject, String annotationPathValue) throws IllegalArgumentException, IllegalAccessException {
List output = new ArrayList<>();
@@ -56,11 +87,166 @@ private static List extractPathData(Model model, Resource subject, Stri
return output;
}
+ // -- Datatyped properties methods
+ protected static final String STRING_CLASS = "java.lang.String";
+ protected static final String URI_CLASS = URI.class.getName();
+ protected static final String COLLECTION_CLASS = Collection.class.getName();
- protected static String concatStrings(String ...message) {
- StringBuilder builder = new StringBuilder();
- for(int index =0; index < message.length; index++)
- builder.append(message[index]);
- return builder.toString();
+ private static final List WRAPPING_PRIMITIVE_TYPES = new ArrayList<>();
+ static {
+ WRAPPING_PRIMITIVE_TYPES.add(STRING_CLASS);
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Long");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Float");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Double");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Character");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Boolean");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Integer");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Short");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Byte");
+ WRAPPING_PRIMITIVE_TYPES.add("java.lang.Number");
+ }
+
+
+
+ protected static boolean isWrappingPrimitive(Field field) {
+ return isWrappingPrimitive(field.getType().getName());
+ }
+
+ protected static boolean isWrappingPrimitive(String fieldName) {
+ return WRAPPING_PRIMITIVE_TYPES.contains(fieldName);
+ }
+
+
+
+
+ protected static boolean isFieldClass(Field field) {
+ return !KehioUtils.isWrappingPrimitive(field) && !KehioUtils.isCollection(field);
+ }
+
+ protected static boolean isFieldString(Field field) {
+ return field.getType().equals(String.class);
+ }
+
+ protected static boolean isFieldURI(Field field) {
+ return field.getType().equals(URI.class);
+ }
+
+ // Collections methods
+
+
+
+ public static boolean isCollection(Field field) {
+ Type fieldType = field.getType();
+ Boolean correctType = fieldType.equals(Collection.class) || fieldType.equals(List.class) || fieldType.equals(Set.class);
+ correctType = correctType || fieldType.equals(Queue.class) || fieldType.equals(Deque.class) || fieldType.equals(SortedSet.class);
+ return correctType;
+ }
+
+ protected static String extractCollectionType(Field field) {
+ ParameterizedType pt = (ParameterizedType) field.getGenericType();
+ String typeName = pt.getTypeName();
+ typeName = typeName.substring(typeName.indexOf(KehioUtils.START_CLASS_TOKEN)+1, typeName.indexOf(KehioUtils.END_CLASS_TOKEN));
+ return typeName;
+ }
+
+ public static boolean isCollectionOfWrappingPrimitive(Field field) {
+ Boolean correctType = isCollection(field) ;
+ correctType &= field.getGenericType() instanceof ParameterizedType;
+ if(correctType) {
+ String innerValue = extractCollectionType(field);
+ correctType &= KehioUtils.isWrappingPrimitive(innerValue);
+ }
+ return correctType;
+ }
+
+
+
+
+ // Map methods
+
+ protected static Entry extractMapTypes(Field field) {
+ ParameterizedType pt = (ParameterizedType) field.getGenericType();
+ String typeName = pt.getTypeName();
+ typeName = typeName.substring(typeName.indexOf(KehioUtils.START_CLASS_TOKEN)+1, typeName.indexOf(KehioUtils.END_CLASS_TOKEN));
+ String[] mapTypes = typeName.split(", ");
+ return Map.entry(mapTypes[0], mapTypes[1]);
+ }
+
+ protected static Class> extractMapValueType(Field field){
+ Class> clazz = null;
+ try {
+ String mapType = KehioUtils.extractMapTypes(field).getValue();
+ clazz = Class.forName(mapType);
+ }catch(Exception e) {
+ throw new IllegalArgumentException(e.toString());
+ }
+ return clazz;
}
+
+ // other
+
+ public static boolean isURI(String url){
+ Boolean isURL = false;
+ try {
+ URI uri = new URI(url);
+ isURL = uri.isAbsolute() ;//contains(":"); // true && (true is implicit as far as no exception is thrown)
+ } catch (Exception exception) {
+ isURL = false;
+ }
+ return isURL;
+ }
+
+ public static boolean isValidResource(String url) {
+ Boolean isURL = false;
+ try {
+ ResourceFactory.createResource(url);
+ isURL = true;
+ }catch(Exception e) {
+ isURL = false;
+ }
+ return isURL;
+ }
+
+ // -- Instantiation methods
+
+ /**
+ * This method receives a field ({@link Collection}, {@link Set}, {@link List}, {@link Queue}, {@link Deque}, or {@link Sortedset}) belonging to an object, and also, a generic collection containing its instantiating values.
+ * As a result, this method instantiates the field of the object with the provided collection.
+ * @param field the field ({@link Collection}, {@link Set}, {@link List}, {@link Queue}, {@link Deque}, or {@link Sortedset})
+ * @param instantiatedCollection the instantiated collection
+ * @param object the generic object that has the provided field and which will be instantiated with the provided collection
+ * @throws IllegalArgumentException in case that the field is not one of {@link Collection}, {@link Set}, {@link List}, {@link Queue}, {@link Deque}, or {@link Sortedset}
+ * @throws IllegalAccessException in case the field does not belongs to the provided object
+ */
+ protected static void instantiateCollection(Field field, Collection