stricter cardinality check in expression parser

Change-Id: Ie48e84e73a9da37134f4062aee7bbbe50d605443

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Klaus Straubinger 2015-04-10 15:25:12 +02:00 committed by Christian Amend
parent 9e232a2d74
commit b76ebe95d1
4 changed files with 45 additions and 58 deletions

View File

@ -366,14 +366,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
if (lastResourcePart == null) {
if (context.contextTypes.size() == 0) {
if(checkFirst && ctx.vNS == null){
if (context.contextTypes.empty()) {
if (checkFirst && ctx.vNS == null) {
throw wrap(new UriParserSemanticException(
"Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '" + odi + "'.",
UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND, odi));
}
throw wrap(new UriParserSemanticException("Resource part '" + odi + "' can only applied on typed "
+ "resource parts",
throw wrap(new UriParserSemanticException(
"Resource part '" + odi + "' can only applied on typed resource parts",
UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
}
source = context.contextTypes.peek();
@ -381,8 +381,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
source = getTypeInformation(lastResourcePart);
if (source.type == null) {
throw wrap(new UriParserSemanticException("Resource part '" + odi + "' can only be applied on typed "
+ "resource parts.", UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
throw wrap(new UriParserSemanticException(
"Resource part '" + odi + "' can only be applied on typed resource parts.",
UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
}
}
@ -400,12 +401,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
if (!(source.type instanceof EdmStructuredType)) {
throw wrap(new UriParserSemanticException("Cannot parse '" + odi
+ "'; previous path segment is not a structural type.",
throw wrap(new UriParserSemanticException(
"Cannot parse '" + odi + "'; previous path segment is not a structural type.",
UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, odi));
}
if (ctx.depth() <= 2 // path evaluation for the resource path
if ((ctx.depth() <= 2 // path evaluation for the resource path
|| lastResourcePart instanceof UriResourceTypedImpl
|| lastResourcePart instanceof UriResourceNavigationPropertyImpl)
&& source.isCollection) {
throw wrap(new UriParserSemanticException("Property '" + odi + "' is not allowed after collection.",
UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, odi));
@ -416,11 +419,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmElement property = structType.getProperty(odi);
if (property == null) {
throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '"
+ structType.getNamespace() + "." + structType.getName() + "'",
+ structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
ctx.depth() > 2 ? // path evaluation inside an expression or for the resource path?
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE :
UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
structType.getFullQualifiedName().toString(), odi));
structType.getFullQualifiedName().getFullQualifiedNameAsString(), odi));
}
if (property instanceof EdmProperty) {

View File

@ -24,7 +24,6 @@ import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
@ -32,7 +31,7 @@ import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.UriResourceProperty;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
@ -102,7 +101,7 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
case NOT:
return unaryOperator.notOperation();
default:
// Can`t happen
// Can't happen.
return throwNotImplemented();
}
}
@ -180,22 +179,19 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
final List<UriResource> uriResourceParts = member.getUriResourceParts();
// UriResourceParts contains at least one UriResource
Property currentProperty = entity.getProperty(uriResourceParts.get(0).toString());
EdmType currentType = ((UriResourcePartTyped) uriResourceParts.get(0)).getType();
if (!(uriResourceParts.get(0) instanceof UriResourceProperty)) {
return throwNotImplemented();
}
EdmProperty currentEdmProperty = bindingTarget.getEntityType()
.getStructuralProperty(uriResourceParts.get(0).toString());
EdmProperty currentEdmProperty = ((UriResourceProperty) uriResourceParts.get(0)).getProperty();
Property currentProperty = entity.getProperty(currentEdmProperty.getName());
for (int i = 1; i < uriResourceParts.size(); i++) {
currentType = ((UriResourcePartTyped) uriResourceParts.get(i)).getType();
if (currentProperty.isComplex()) {
currentEdmProperty = ((UriResourceProperty) uriResourceParts.get(i)).getProperty();
final List<Property> complex = currentProperty.asComplex().getValue();
for (final Property innerProperty : complex) {
if (innerProperty.getName().equals(uriResourceParts.get(i).toString())) {
EdmComplexType edmComplexType = (EdmComplexType) currentEdmProperty.getType();
currentEdmProperty = edmComplexType.getStructuralProperty(uriResourceParts.get(i).toString());
if (innerProperty.getName().equals(currentEdmProperty.getName())) {
currentProperty = innerProperty;
break;
}
@ -203,7 +199,7 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
}
}
return new TypedOperand(currentProperty.getValue(), currentType, currentEdmProperty);
return new TypedOperand(currentProperty.getValue(), currentEdmProperty.getType(), currentEdmProperty);
}
@Override

View File

@ -2950,21 +2950,27 @@ public class TestFullResourcePath {
testFilter.runOnETTwoKeyNavEx("invalid")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testFilter.runOnETTwoKeyNavEx("PropertyComp")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
// TODO: This should throw an exception because the top node of the filter tree must be boolean.
//testFilter.runOnETTwoKeyNavEx("PropertyComp")
// .isExSemantic(UriParserSemanticException.MessageKeys.XYZ);
testFilter.runOnETTwoKeyNavEx("PropertyComp/invalid")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testFilter.runOnETTwoKeyNavEx("PropertyComp/concat('a','b')")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyDate eq 1")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyString eq 1")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
// TODO: These should throw exceptions because the types are incompatible.
//testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
// .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
//testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyDate eq 1")
// .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
//testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyString eq 1")
// .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt64 eq 1")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/PropertyInt16 gt 42")
.isExSemantic(UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION);
testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/NavPropertyETTwoKeyNavOne eq null")
.isExSemantic(UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION);
testFilter.runOnETAllPrim("PropertySByte eq PropertySByte")
.is("<<PropertySByte> eq <PropertySByte>>")

View File

@ -193,22 +193,13 @@ public class FilterValidator implements TestValidator {
}
public FilterValidator runUriEx(final String path, final String query) {
Parser parser = new Parser();
UriInfo uriInfo = null;
exception = null;
try {
uriInfo = parser.parseUri(path, query, null, edm);
} catch (UriParserException e) {
new Parser().parseUri(path, query, null, edm);
fail("Expected exception not thrown.");
} catch (final UriParserException e) {
exception = e;
return this;
}
if (uriInfo.getKind() != UriInfoKind.resource) {
fail("Filtervalidator can only be used on resourcePaths");
}
setFilter((FilterOptionImpl) uriInfo.getFilterOption());
curExpression = filter.getExpression();
return this;
}
@ -227,22 +218,13 @@ public class FilterValidator implements TestValidator {
}
public FilterValidator runUriOrderByEx(final String path, final String query) {
Parser parser = new Parser();
UriInfo uriInfo = null;
exception = null;
try {
uriInfo = parser.parseUri(path, query, null, edm);
new Parser().parseUri(path, query, null, edm);
fail("Expected exception not thrown.");
} catch (UriParserException e) {
} catch (final UriParserException e) {
exception = e;
return this;
}
if (uriInfo.getKind() != UriInfoKind.resource) {
fail("Filtervalidator can only be used on resourcePaths");
}
setOrderBy((OrderByOptionImpl) uriInfo.getOrderByOption());
return this;
}