|
20 | 20 | import java.util.Optional;
|
21 | 21 | import java.util.function.Function;
|
22 | 22 | import java.util.function.Predicate;
|
| 23 | + |
23 | 24 | import javax.xml.datatype.DatatypeConfigurationException;
|
24 | 25 | import javax.xml.datatype.DatatypeFactory;
|
25 | 26 | import javax.xml.datatype.Duration;
|
26 | 27 | import javax.xml.datatype.XMLGregorianCalendar;
|
27 | 28 |
|
28 | 29 | import jakarta.xml.bind.DatatypeConverter;
|
| 30 | +import org.apache.commons.lang3.NotImplementedException; |
| 31 | +import org.apache.jena.datatypes.DatatypeFormatException; |
29 | 32 | import org.apache.jena.datatypes.RDFDatatype;
|
30 | 33 | import org.apache.jena.datatypes.TypeMapper;
|
31 | 34 | import org.apache.jena.datatypes.xsd.XSDDatatype;
|
32 | 35 | import org.apache.jena.datatypes.xsd.impl.RDFLangString;
|
33 |
| -import org.apache.jena.ext.xerces.impl.dv.XSSimpleType; |
34 |
| -import org.apache.jena.ext.xerces.impl.dv.xs.ExtendedSchemaDVFactoryImpl; |
| 36 | +import org.apache.jena.graph.impl.LiteralLabel; |
35 | 37 | import org.apache.jena.rdf.model.Resource;
|
36 | 38 | import org.slf4j.Logger;
|
37 | 39 | import org.slf4j.LoggerFactory;
|
38 | 40 |
|
| 41 | +/** |
| 42 | + * The custom RDF type implementations that have deterministic and typed parsers and unparsers (i.e., serializers). |
| 43 | + * |
| 44 | + * @param <T> the Java class that represents values for the type |
| 45 | + */ |
39 | 46 | // the order of the variables is required because of the way they reference each other
|
40 | 47 | public class SammXsdType<T> extends XSDDatatype implements SammType<T> {
|
41 | 48 | private static final Logger LOG = LoggerFactory.getLogger( SammXsdType.class );
|
42 | 49 | public static DatatypeFactory datatypeFactory;
|
43 | 50 |
|
44 |
| - private final Class<T> correspondingJavaClass; |
45 | 51 | private final Function<String, T> parser;
|
46 | 52 | private final Function<T, String> unparser;
|
47 | 53 | private final Predicate<String> lexicalValidator;
|
48 | 54 | private static boolean checking = true;
|
49 |
| - private static final ExtendedSchemaDVFactoryImpl EXTENDED_SCHEMA_DV_FACTORY = new ExtendedSchemaDVFactoryImpl(); |
50 |
| - |
51 |
| - public SammXsdType( final Resource dataTypeResource, final Class<T> correspondingJavaClass, |
52 |
| - final Function<String, T> parser, |
53 |
| - final Function<T, String> unparser, |
54 |
| - final Predicate<String> lexicalValidator ) { |
55 |
| - super( dataTypeResource.getLocalName() ); |
56 |
| - this.correspondingJavaClass = correspondingJavaClass; |
57 |
| - this.parser = parser; |
58 |
| - this.unparser = unparser; |
59 |
| - this.lexicalValidator = lexicalValidator; |
60 |
| - } |
61 | 55 |
|
62 |
| - private SammXsdType( final Resource dataTypeResource, final XSSimpleType xstype, |
| 56 | + protected SammXsdType( final Resource dataTypeResource, |
63 | 57 | final Class<T> correspondingJavaClass,
|
64 | 58 | final Function<String, T> parser,
|
65 | 59 | final Function<T, String> unparser,
|
66 | 60 | final Predicate<String> lexicalValidator ) {
|
67 |
| - //In the namespace the hash symbol should be removed, because jena defines the namespace differently. |
68 |
| - super( xstype, dataTypeResource.getNameSpace().replace( "#", "" ) ); |
69 |
| - this.correspondingJavaClass = correspondingJavaClass; |
| 61 | + super( dataTypeResource.getLocalName() ); |
| 62 | + javaClass = correspondingJavaClass; |
70 | 63 | this.parser = parser;
|
71 | 64 | this.unparser = unparser;
|
72 | 65 | this.lexicalValidator = lexicalValidator;
|
@@ -139,10 +132,9 @@ private SammXsdType( final Resource dataTypeResource, final XSSimpleType xstype,
|
139 | 132 | value -> datatypeFactory.newXMLGregorianCalendar( value ), XMLGregorianCalendar::toXMLFormat,
|
140 | 133 | XSDDatatype.XSDdateTime::isValid );
|
141 | 134 |
|
142 |
| - public static final SammXsdType<XMLGregorianCalendar> DATE_TIME_STAMP = new SammXsdType<>( |
| 135 | + public static final SammExtendedXsdType<XMLGregorianCalendar> DATE_TIME_STAMP = new SammExtendedXsdType<>( |
143 | 136 | org.apache.jena.vocabulary.XSD.dateTimeStamp,
|
144 |
| - EXTENDED_SCHEMA_DV_FACTORY.getBuiltInType( org.apache.jena.vocabulary.XSD.dateTimeStamp.getLocalName() ), |
145 |
| - XMLGregorianCalendar.class, value -> datatypeFactory.newXMLGregorianCalendar( value ), |
| 137 | + XMLGregorianCalendar.class, value -> SammXsdType.datatypeFactory.newXMLGregorianCalendar( value ), |
146 | 138 | XMLGregorianCalendar::toXMLFormat, XSDDatatype.XSDdateTimeStamp::isValid );
|
147 | 139 |
|
148 | 140 | public static final SammXsdType<XMLGregorianCalendar> G_YEAR = new SammXsdType<>(
|
@@ -174,16 +166,14 @@ private SammXsdType( final Resource dataTypeResource, final XSSimpleType xstype,
|
174 | 166 | org.apache.jena.vocabulary.XSD.duration, Duration.class, value -> datatypeFactory.newDuration( value ),
|
175 | 167 | Duration::toString, XSDDatatype.XSDduration::isValid );
|
176 | 168 |
|
177 |
| - public static final SammXsdType<Duration> YEAR_MONTH_DURATION = new SammXsdType<>( |
| 169 | + public static final SammExtendedXsdType<Duration> YEAR_MONTH_DURATION = new SammExtendedXsdType<>( |
178 | 170 | org.apache.jena.vocabulary.XSD.yearMonthDuration,
|
179 |
| - EXTENDED_SCHEMA_DV_FACTORY.getBuiltInType( org.apache.jena.vocabulary.XSD.yearMonthDuration.getLocalName() ), |
180 |
| - Duration.class, value -> datatypeFactory.newDurationYearMonth( value ), Duration::toString, |
| 171 | + Duration.class, value -> SammXsdType.datatypeFactory.newDurationYearMonth( value ), Duration::toString, |
181 | 172 | XSDDatatype.XSDyearMonthDuration::isValid );
|
182 | 173 |
|
183 |
| - public static final SammXsdType<Duration> DAY_TIME_DURATION = new SammXsdType<>( |
| 174 | + public static final SammExtendedXsdType<Duration> DAY_TIME_DURATION = new SammExtendedXsdType<>( |
184 | 175 | org.apache.jena.vocabulary.XSD.dayTimeDuration,
|
185 |
| - EXTENDED_SCHEMA_DV_FACTORY.getBuiltInType( org.apache.jena.vocabulary.XSD.dayTimeDuration.getLocalName() ), |
186 |
| - Duration.class, value -> datatypeFactory.newDurationDayTime( value ), Duration::toString, |
| 176 | + Duration.class, value -> SammXsdType.datatypeFactory.newDurationDayTime( value ), Duration::toString, |
187 | 177 | XSDDatatype.XSDdayTimeDuration::isValid );
|
188 | 178 |
|
189 | 179 | public static final SammXsdType<Byte> BYTE = new SammXsdType<>( org.apache.jena.vocabulary.XSD.xbyte,
|
@@ -245,10 +235,6 @@ private SammXsdType( final Resource dataTypeResource, final XSSimpleType xstype,
|
245 | 235 | value -> URI.create( (String) XSDDatatype.XSDanyURI.parse( value ) ),
|
246 | 236 | URI::toString, XSDDatatype.XSDanyURI::isValid );
|
247 | 237 |
|
248 |
| - @SuppressWarnings( "checkstyle:LambdaParameterName" ) |
249 |
| - public static final SammXsdType<String> STRING = new SammXsdType<>( |
250 |
| - org.apache.jena.vocabulary.XSD.xstring, String.class, Function.identity(), Function.identity(), __ -> true ); |
251 |
| - |
252 | 238 | public static final List<RDFDatatype> ALL_TYPES = List
|
253 | 239 | .of( XSDDatatype.XSDstring, BOOLEAN, DECIMAL, INTEGER, DOUBLE, FLOAT, DATE, TIME, DATE_TIME, DATE_TIME_STAMP,
|
254 | 240 | G_YEAR, G_MONTH, G_YEAR_MONTH, G_DAY, G_MONTH_DAY, DURATION, YEAR_MONTH_DURATION, DAY_TIME_DURATION,
|
@@ -311,9 +297,10 @@ public boolean isValid( final String lexicalForm ) {
|
311 | 297 | return lexicalValidator.test( lexicalForm );
|
312 | 298 | }
|
313 | 299 |
|
| 300 | + @SuppressWarnings( "unchecked" ) |
314 | 301 | @Override
|
315 | 302 | public Class<T> getJavaClass() {
|
316 |
| - return correspondingJavaClass; |
| 303 | + return (Class<T>) javaClass; |
317 | 304 | }
|
318 | 305 |
|
319 | 306 | private static boolean setupPerformed = false;
|
@@ -349,4 +336,116 @@ public static Class<?> getJavaTypeForMetaModelType( final Resource type ) {
|
349 | 336 | .findAny()
|
350 | 337 | .orElseThrow( () -> new IllegalStateException( "Invalid data type " + type + " found in model." ) );
|
351 | 338 | }
|
| 339 | + |
| 340 | + /** |
| 341 | + * Separate implementation for the "extended" RDF types that can not be based on {@link XSDDatatype}. |
| 342 | + * |
| 343 | + * @param <T> the Java class that represents values for the type |
| 344 | + */ |
| 345 | + public static class SammExtendedXsdType<T> implements SammType<T> { |
| 346 | + private final String uri; |
| 347 | + private final Class<T> javaClass; |
| 348 | + private final Function<String, T> parser; |
| 349 | + private final Function<T, String> unparser; |
| 350 | + private final Predicate<String> lexicalValidator; |
| 351 | + |
| 352 | + public SammExtendedXsdType( |
| 353 | + final Resource dataTypeResource, |
| 354 | + final Class<T> javaClass, |
| 355 | + final Function<String, T> parser, |
| 356 | + final Function<T, String> unparser, |
| 357 | + final Predicate<String> lexicalValidator |
| 358 | + ) { |
| 359 | + uri = dataTypeResource.getURI(); |
| 360 | + this.javaClass = javaClass; |
| 361 | + this.parser = parser; |
| 362 | + this.unparser = unparser; |
| 363 | + this.lexicalValidator = lexicalValidator; |
| 364 | + } |
| 365 | + |
| 366 | + @Override |
| 367 | + public Optional<T> parseTyped( final String lexicalForm ) { |
| 368 | + try { |
| 369 | + return Optional.of( parser.apply( lexicalForm ) ); |
| 370 | + } catch ( final RuntimeException exception ) { |
| 371 | + if ( checking ) { |
| 372 | + throw exception; |
| 373 | + } |
| 374 | + } |
| 375 | + return Optional.empty(); |
| 376 | + } |
| 377 | + |
| 378 | + @Override |
| 379 | + public String unparseTyped( final T value ) { |
| 380 | + return unparser.apply( value ); |
| 381 | + } |
| 382 | + |
| 383 | + @Override |
| 384 | + public String getURI() { |
| 385 | + return uri; |
| 386 | + } |
| 387 | + |
| 388 | + @Override |
| 389 | + @SuppressWarnings( "unchecked" ) |
| 390 | + public String unparse( final Object value ) { |
| 391 | + return unparseTyped( (T) value ); |
| 392 | + } |
| 393 | + |
| 394 | + @Override |
| 395 | + public Object parse( final String lexicalForm ) throws DatatypeFormatException { |
| 396 | + try { |
| 397 | + return parser.apply( lexicalForm ); |
| 398 | + } catch ( final Exception exception ) { |
| 399 | + if ( checking ) { |
| 400 | + throw exception; |
| 401 | + } |
| 402 | + } |
| 403 | + return lexicalForm; |
| 404 | + } |
| 405 | + |
| 406 | + @Override |
| 407 | + public boolean isValid( final String lexicalForm ) { |
| 408 | + return lexicalValidator.test( lexicalForm ); |
| 409 | + } |
| 410 | + |
| 411 | + @Override |
| 412 | + public boolean isValidValue( final Object valueForm ) { |
| 413 | + return isValid( unparse( valueForm ) ); |
| 414 | + } |
| 415 | + |
| 416 | + @Override |
| 417 | + public boolean isValidLiteral( final LiteralLabel lit ) { |
| 418 | + return isValid( lit.getLexicalForm() ); |
| 419 | + } |
| 420 | + |
| 421 | + @Override |
| 422 | + public boolean isEqual( final LiteralLabel value1, final LiteralLabel value2 ) { |
| 423 | + return value1.getLexicalForm().equals( value2.getLexicalForm() ); |
| 424 | + } |
| 425 | + |
| 426 | + @Override |
| 427 | + public int getHashCode( final LiteralLabel lit ) { |
| 428 | + return lit.getValueHashCode(); |
| 429 | + } |
| 430 | + |
| 431 | + @Override |
| 432 | + public Class<T> getJavaClass() { |
| 433 | + return javaClass; |
| 434 | + } |
| 435 | + |
| 436 | + @Override |
| 437 | + public Object cannonicalise( final Object value ) { |
| 438 | + return value; |
| 439 | + } |
| 440 | + |
| 441 | + @Override |
| 442 | + public Object extendedTypeDefinition() { |
| 443 | + throw new NotImplementedException(); |
| 444 | + } |
| 445 | + |
| 446 | + @Override |
| 447 | + public RDFDatatype normalizeSubType( final Object value, final RDFDatatype dt ) { |
| 448 | + return this; |
| 449 | + } |
| 450 | + } |
352 | 451 | }
|
0 commit comments