Skip to content

Commit c215cdc

Browse files
authored
Merge pull request #765 from bci-oss/764-process-invalid-literal-values
Report invalid scalar values like syntax errors
2 parents 1b5e4ef + 42f66c6 commit c215cdc

File tree

14 files changed

+356
-151
lines changed

14 files changed

+356
-151
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel;
15+
16+
public class ValueParsingException extends RuntimeException {
17+
private final String type;
18+
private final Object value;
19+
private long line;
20+
private long column;
21+
22+
public ValueParsingException( final String type, final Object value ) {
23+
this.type = type;
24+
this.value = value;
25+
}
26+
27+
public ValueParsingException( final String type, final Object value, final Throwable cause ) {
28+
super( cause );
29+
this.type = type;
30+
this.value = value;
31+
}
32+
33+
public String getType() {
34+
return type;
35+
}
36+
37+
public Object getValue() {
38+
return value;
39+
}
40+
41+
public ValueParsingException setLine( final long line ) {
42+
this.line = line;
43+
return this;
44+
}
45+
46+
public ValueParsingException setColumn( final long column ) {
47+
this.column = column;
48+
return this;
49+
}
50+
51+
public long getLine() {
52+
return line;
53+
}
54+
55+
public long getColumn() {
56+
return column;
57+
}
58+
}

core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/metamodel/datatype/SammXsdType.java

Lines changed: 159 additions & 85 deletions
Large diffs are not rendered by default.

core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/metamodel/vocabulary/SAMM.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@
1212
*/
1313
package org.eclipse.esmf.metamodel.vocabulary;
1414

15-
import java.util.List;
16-
1715
import org.eclipse.esmf.samm.KnownVersion;
1816

19-
import com.google.common.collect.ImmutableList;
2017
import org.apache.jena.rdf.model.Property;
2118
import org.apache.jena.rdf.model.Resource;
2219

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ParserException.java

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,77 @@
1313

1414
package org.eclipse.esmf.aspectmodel.resolver.exceptions;
1515

16+
import java.util.Optional;
17+
import java.util.regex.Matcher;
18+
import java.util.regex.Pattern;
19+
20+
import org.apache.jena.riot.RiotException;
21+
22+
/**
23+
* Represents the context information of a parser (syntax) error: The location, source document and description
24+
*/
1625
public class ParserException extends RuntimeException {
26+
/**
27+
* The pattern to parse {@link RiotException}'s messages.
28+
* RiotException's message looks like this:
29+
* [line: 17, col: 2 ] Triples not terminated by DOT
30+
*/
31+
private static final Pattern PATTERN = Pattern.compile( "\\[ *line: *(\\d+), *col: *(\\d+) *] *(.*)" );
1732
private final String sourceDocument;
33+
private final long line;
34+
private final long column;
35+
36+
/**
37+
* Constructor: Parse a RiotException
38+
*
39+
* @param exception the cause
40+
* @param sourceDocument the source document
41+
*/
42+
public ParserException( final RiotException exception, final String sourceDocument ) {
43+
super( getRiotMessage( exception.getMessage() ).orElse( "Syntax error: " + exception.getMessage() ), exception );
44+
this.sourceDocument = sourceDocument;
45+
final Matcher matcher = PATTERN.matcher( exception.getMessage() );
46+
if ( matcher.find() ) {
47+
line = Long.parseLong( matcher.group( 1 ) );
48+
column = Long.parseLong( matcher.group( 2 ) );
49+
} else {
50+
line = -1;
51+
column = -1;
52+
}
53+
}
1854

19-
public ParserException( final Throwable cause, final String sourceDocument ) {
20-
super( cause.getMessage(), cause );
55+
/**
56+
* Constructor: Create a parser exception when the problem location is already known
57+
*
58+
* @param line the line of the parser problem
59+
* @param column the column of the parser problem
60+
* @param message the message
61+
* @param sourceDocument the source document
62+
*/
63+
public ParserException( final long line, final long column, final String message, final String sourceDocument ) {
64+
super( message );
2165
this.sourceDocument = sourceDocument;
66+
this.line = line;
67+
this.column = column;
68+
}
69+
70+
private static Optional<String> getRiotMessage( final String riotMessage ) {
71+
final Matcher matcher = PATTERN.matcher( riotMessage );
72+
if ( matcher.find() ) {
73+
return Optional.of( matcher.group( 3 ) );
74+
}
75+
return Optional.empty();
2276
}
2377

2478
public String getSourceDocument() {
2579
return sourceDocument;
2680
}
81+
82+
public long getLine() {
83+
return line;
84+
}
85+
86+
public long getColumn() {
87+
return column;
88+
}
2789
}

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/modelfile/ModelFiles.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
package org.eclipse.esmf.aspectmodel.resolver.parser;
1515

16+
import org.eclipse.esmf.aspectmodel.ValueParsingException;
17+
1618
import org.apache.jena.datatypes.RDFDatatype;
1719
import org.apache.jena.graph.Graph;
1820
import org.apache.jena.graph.Node;
@@ -44,9 +46,15 @@ public String getBaseURI() {
4446

4547
@Override
4648
public Node create( final Node currentGraph, final Token token ) {
47-
final Node node = parserProfile.create( currentGraph, token );
48-
TokenRegistry.put( node, new SmartToken( token ) );
49-
return node;
49+
try {
50+
final Node node = parserProfile.create( currentGraph, token );
51+
TokenRegistry.put( node, new SmartToken( token ) );
52+
return node;
53+
} catch ( final ValueParsingException exception ) {
54+
exception.setLine( token.getLine() );
55+
exception.setColumn( token.getColumn() );
56+
throw exception;
57+
}
5058
}
5159

5260
@Override

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.stream.Collectors;
2424
import javax.annotation.Nullable;
2525

26+
import org.eclipse.esmf.aspectmodel.ValueParsingException;
2627
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException;
2728
import org.eclipse.esmf.aspectmodel.resolver.parser.ReaderRiotTurtle;
2829
import org.eclipse.esmf.metamodel.datatype.SammXsdType;
@@ -100,12 +101,9 @@ public static Try<Model> loadTurtle( @Nullable final String modelContent ) {
100101
.lang( Lang.TURTLE )
101102
.toModel();
102103
return Try.success( streamModel );
103-
} catch ( final IllegalArgumentException exception ) {
104-
LOG.error( "Invalid value encountered in Aspect Model.", exception );
105-
final String incorrectDataTypeDefinitionMessage = "%s is not a valid value for the defined data type.";
106-
final String formattedErrorMessage = String
107-
.format( incorrectDataTypeDefinitionMessage, exception.getMessage() );
108-
return Try.failure( new IllegalArgumentException( formattedErrorMessage ) );
104+
} catch ( final ValueParsingException exception ) {
105+
return Try.failure( new ParserException( exception.getLine(), exception.getColumn(),
106+
"'%s' is no valid value for type %s".formatted( exception.getValue(), exception.getType() ), modelContent ) );
109107
} catch ( final IOException exception ) {
110108
return Try.failure( exception );
111109
} catch ( final RiotException exception ) {

core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.esmf.aspectmodel.AspectLoadingException;
2727
import org.eclipse.esmf.aspectmodel.AspectModelFile;
2828
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
29+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException;
2930
import org.eclipse.esmf.metamodel.AbstractEntity;
3031
import org.eclipse.esmf.metamodel.AspectModel;
3132
import org.eclipse.esmf.metamodel.ComplexType;
@@ -70,6 +71,16 @@ void testFileWithInvalidEncoding() {
7071
.hasMessageContaining( "Encountered invalid encoding" );
7172
}
7273

74+
@Test
75+
void testAspectModelWithInvalidUri() {
76+
assertThatThrownBy( () -> TestResources.load( InvalidTestAspect.INVALID_URI ) )
77+
.isInstanceOfSatisfying( ParserException.class, parserException -> {
78+
assertThat( parserException.getMessage() ).contains( "invalid with spaces" );
79+
assertThat( parserException.getLine() ).isNotEqualTo( -1 ).isNotEqualTo( 0 );
80+
assertThat( parserException.getColumn() ).isNotEqualTo( -1 ).isNotEqualTo( 0 );
81+
} );
82+
}
83+
7384
@Test
7485
void testOfAbstractEntityCyclomaticCreation() {
7586
final Map<String, ComplexType> entities =

core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoaderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void turtleLoaderFailsWithNullPointerIfPrefixIsNotDefined() {
4343
final Try<Model> tryModel = TurtleLoader.loadTurtle( new ByteArrayInputStream( MODEL.getBytes( StandardCharsets.UTF_8 ) ) );
4444
assertThat( tryModel.isFailure() ).isTrue();
4545
assertThat( tryModel.getCause() ).isInstanceOfSatisfying( ParserException.class, parserException -> {
46-
assertThat( parserException.getMessage() ).contains( "[line: 2, col: 13] Undefined prefix: aPrefix" );
46+
assertThat( parserException.getMessage() ).contains( "Undefined prefix: aPrefix" );
4747
} );
4848
} ).doesNotThrowAnyException();
4949
}

core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/validation/services/AspectModelValidator.java

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
import java.io.File;
1717
import java.util.List;
1818
import java.util.function.Supplier;
19-
import java.util.regex.Matcher;
20-
import java.util.regex.Pattern;
2119

2220
import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader;
2321
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException;
@@ -80,18 +78,9 @@ public Either<List<Violation>, AspectModel> loadModel( final Supplier<AspectMode
8078
model = aspectModelSupplier.get();
8179
return Either.right( model );
8280
} catch ( final ParserException exception ) { // Syntax error
83-
// RiotException's message looks like this:
84-
// [line: 17, col: 2 ] Triples not terminated by DOT
85-
final Pattern pattern = Pattern.compile( "\\[ *line: *(\\d+), *col: *(\\d+) *] *(.*)" );
86-
final Matcher matcher = pattern.matcher( exception.getMessage() );
87-
if ( matcher.find() ) {
88-
final long line = Long.parseLong( matcher.group( 1 ) );
89-
final long column = Long.parseLong( matcher.group( 2 ) );
90-
final String message = matcher.group( 3 );
91-
return Either.left( List.of( new InvalidSyntaxViolation( message, exception.getSourceDocument(), line, column ) ) );
92-
}
93-
return Either.left(
94-
List.of( new InvalidSyntaxViolation( "Syntax error: " + exception.getMessage(), exception.getSourceDocument(), -1, -1 ) ) );
81+
return Either.left( List.of(
82+
new InvalidSyntaxViolation( exception.getMessage(), exception.getSourceDocument(), exception.getLine(),
83+
exception.getColumn() ) ) );
9584
} catch ( final Exception exception ) { // Any other exception, e.g., resolution exception
9685
return Either.left( List.of( new ProcessingViolation( exception.getMessage(), exception ) ) );
9786
}

0 commit comments

Comments
 (0)