[OLINGO-801] UriParser supports Complex / Entity Parameters.
This commit is contained in:
parent
f221962f72
commit
3584e1d71d
|
@ -29,6 +29,7 @@ STRING : '\'' -> more, pushMode(MODE_STRING) ;
|
|||
QUOTATION_MARK : '\u0022' -> more, pushMode(MODE_JSON_STRING); //reads up to next unescaped "
|
||||
SEARCH_INLINE : '$search' -> pushMode(MODE_SYSTEM_QUERY_SEARCH); //
|
||||
FRAGMENT : '#' -> pushMode(MODE_FRAGMENT); //
|
||||
STRING_JSON : '"' -> more, pushMode(MODE_JSON_STRING); //reads up to next unescaped "
|
||||
|
||||
GEOGRAPHY : G E O G R A P H Y SQUOTE -> pushMode(MODE_ODATA_GEO); //TODO make case insensitive
|
||||
GEOMETRY : G E O M E T R Y SQUOTE -> pushMode(MODE_ODATA_GEO);
|
||||
|
@ -364,8 +365,11 @@ mode MODE_JSON_STRING;
|
|||
// Any """ characters inside a string are escaped with "\".
|
||||
//;==============================================================================
|
||||
|
||||
STRING_IN_JSON : ('\\"' | ~[\u0022] )* '"' -> popMode;
|
||||
ERROR_CHARACTER_jsm : EOF | .;
|
||||
STRING_IN_JSON : (ESCAPED_JSON_CHAR | ~["\\])* '"' -> popMode;
|
||||
fragment ESCAPED_JSON_CHAR : '\\' (["\\/bfnrt] | UNICODE_CHAR);
|
||||
fragment UNICODE_CHAR : 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;
|
||||
fragment HEX_DIGIT : [0-9a-fA-F];
|
||||
ERROR_CHARACTER_jsm : EOF | .;
|
||||
|
||||
//;==============================================================================
|
||||
mode MODE_ODATA_GEO;
|
||||
|
|
|
@ -205,6 +205,7 @@ commonExpr : OPEN commonExpr CLOSE
|
|||
| rootExpr #altRoot // $...
|
||||
| AT odataIdentifier #altAlias // @...
|
||||
| primitiveLiteral #altLiteral // ...
|
||||
| arrayOrObject #altJson
|
||||
;
|
||||
|
||||
unary : (MINUS| NOT) ;
|
||||
|
@ -309,11 +310,15 @@ json_value : jsonPrimitiv
|
|||
| json_array;
|
||||
|
||||
json_object : BEGIN_OBJECT
|
||||
STRING_IN_JSON
|
||||
WSP? COLON WSP?
|
||||
json_value
|
||||
(
|
||||
json_key_value_pair
|
||||
(COMMA json_key_value_pair)*
|
||||
)?
|
||||
END_OBJECT;
|
||||
|
||||
json_key_value_pair : STRING_IN_JSON
|
||||
WSP? COLON WSP?
|
||||
json_value;
|
||||
|
||||
//; JSON syntax: adapted to URI restrictions from [RFC4627]
|
||||
jsonPrimitiv : STRING_IN_JSON
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoAll;
|
||||
import org.apache.olingo.server.api.uri.UriInfoBatch;
|
||||
|
@ -36,6 +36,7 @@ import org.apache.olingo.server.api.uri.UriInfoKind;
|
|||
import org.apache.olingo.server.api.uri.UriInfoMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriInfoService;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
|
||||
|
@ -63,8 +64,8 @@ public class UriInfoImpl implements UriInfo {
|
|||
private EdmEntityType entityTypeCast; // for $entity
|
||||
|
||||
private List<CustomQueryOptionImpl> customQueryOptions = new ArrayList<CustomQueryOptionImpl>();
|
||||
private Map<String, String> aliasToValue = new HashMap<String, String>();
|
||||
|
||||
private Map<String, UriParameter> aliasValues = new HashMap<String, UriParameter>();
|
||||
|
||||
private Map<SystemQueryOptionKind, SystemQueryOption> systemQueryOptions =
|
||||
new HashMap<SystemQueryOptionKind, SystemQueryOption>();
|
||||
|
||||
|
@ -138,9 +139,18 @@ public class UriInfoImpl implements UriInfo {
|
|||
|
||||
@Override
|
||||
public String getValueForAlias(final String alias) {
|
||||
return aliasToValue.get(alias);
|
||||
final UriParameter parameter = aliasValues.get(alias);
|
||||
return parameter == null ? null : parameter.getText();
|
||||
}
|
||||
|
||||
public UriParameter getAlias(final String key) {
|
||||
return aliasValues.get(key);
|
||||
}
|
||||
|
||||
public void addAlias(final String key, UriParameter parameter) {
|
||||
aliasValues.put(key, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmEntityType getEntityTypeCast() {
|
||||
return entityTypeCast;
|
||||
|
@ -235,9 +245,6 @@ public class UriInfoImpl implements UriInfo {
|
|||
|
||||
public void addCustomQueryOption(final CustomQueryOptionImpl item) {
|
||||
customQueryOptions.add(item);
|
||||
if (item.getName().startsWith("@")) {
|
||||
aliasToValue.put(item.getName(), item.getText());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,5 +304,4 @@ public class UriInfoImpl implements UriInfo {
|
|||
public Collection<SystemQueryOption> getSystemQueryOptions() {
|
||||
return Collections.unmodifiableCollection(systemQueryOptions.values());
|
||||
}
|
||||
|
||||
}
|
|
@ -30,8 +30,8 @@ import org.antlr.v4.runtime.RecognitionException;
|
|||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.atn.PredictionMode;
|
||||
import org.antlr.v4.runtime.misc.ParseCancellationException;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
|
@ -42,6 +42,7 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
|
|||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
|
||||
import org.apache.olingo.server.core.uri.UriInfoImpl;
|
||||
import org.apache.olingo.server.core.uri.UriParameterImpl;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriLexer;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
|
||||
|
@ -65,11 +66,14 @@ import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
|
|||
import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
|
||||
|
||||
public class Parser {
|
||||
private static final String ATOM = "atom";
|
||||
private static final String JSON = "json";
|
||||
private static final String XML = "xml";
|
||||
private static final String AT = "@";
|
||||
private static final String NULL = "null";
|
||||
int logLevel = 0;
|
||||
|
||||
private enum ParserEntryRules {
|
||||
|
@ -271,7 +275,26 @@ public class Parser {
|
|||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
|
||||
}
|
||||
} else {
|
||||
CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
|
||||
if (option.name.startsWith(AT)) {
|
||||
final FilterExpressionEOFContext filterExpCtx =
|
||||
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
|
||||
final ExpressionImpl expression = ((FilterOptionImpl) uriParseTreeVisitor
|
||||
.visitFilterExpressionEOF(filterExpCtx)).getExpression();
|
||||
|
||||
final UriParameterImpl parameter = new UriParameterImpl();
|
||||
parameter.setAlias(option.name);
|
||||
parameter.setExpression(expression);
|
||||
parameter.setText(NULL.equals(option.value) ? null : option.value);
|
||||
|
||||
if(context.contextUriInfo.getAlias(option.name) == null) {
|
||||
context.contextUriInfo.addAlias(option.name, parameter);
|
||||
} else {
|
||||
throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
|
||||
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
|
||||
}
|
||||
}
|
||||
|
||||
final CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
|
||||
customOption.setName(option.name);
|
||||
customOption.setText(option.value);
|
||||
context.contextUriInfo.addCustomQueryOption(customOption);
|
||||
|
|
|
@ -95,7 +95,12 @@ public class UriContext {
|
|||
*/
|
||||
public UriInfoImpl contextUriInfo;
|
||||
public boolean contextReadingFunctionParameters;
|
||||
|
||||
|
||||
/**
|
||||
* Set to true if the parser operates on query part.
|
||||
*/
|
||||
public boolean contextReadingQueryPart;
|
||||
|
||||
public UriContext() {
|
||||
|
||||
contextExpandItemPath = null;
|
||||
|
|
|
@ -95,6 +95,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltHasContext;
|
|||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ArrayOrObjectContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext;
|
||||
|
@ -116,6 +117,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.EnumLiteralContex
|
|||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandCountOptionContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandOptionContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext;
|
||||
|
@ -179,6 +181,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalOffsetMinute
|
|||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalsecondsMethodCallExprContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.TrimMethodCallExprContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.YearMethodCallExprContext;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
|
||||
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
|
||||
|
@ -306,7 +309,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
final boolean checkFirst =
|
||||
context.contextUriInfo.getLastResourcePart() == null
|
||||
|| context.contextUriInfo.getLastResourcePart() instanceof UriResourceRootImpl;
|
||||
|| context.contextUriInfo.getLastResourcePart() instanceof UriResourceRootImpl;
|
||||
|
||||
String odi = ctx.vODI.getText();
|
||||
|
||||
|
@ -361,6 +364,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
// check FunctionImport
|
||||
EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(odi);
|
||||
|
||||
if(edmFunctionImport != null && context.contextReadingQueryPart) {
|
||||
throw wrap(new UriParserSemanticException("Function Imports are not allowed in $filter or $orderby",
|
||||
UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED, odi));
|
||||
}
|
||||
|
||||
if (edmFunctionImport != null
|
||||
&& (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
|
||||
|| parts.get(0) instanceof UriResourceRoot)) {
|
||||
|
@ -399,7 +408,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
+ "' with parameters [" + tmp.toString() + "] not found",
|
||||
UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, edmFunctionImport.getName(), tmp.toString()));
|
||||
}
|
||||
|
||||
|
||||
ensureNamespaceIsNull(ctx.vNS);
|
||||
uriResource.setFunction(edmFunctionImport.getUnboundFunction(names));
|
||||
context.contextUriInfo.addResourcePart(uriResource);
|
||||
|
@ -466,8 +475,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '"
|
||||
+ 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,
|
||||
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE
|
||||
: UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
|
||||
structType.getFullQualifiedName().getFullQualifiedNameAsString(), odi));
|
||||
}
|
||||
|
||||
|
@ -492,7 +501,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
"Navigation properties in expand system query options must not be followed by a key.",
|
||||
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
|
||||
}
|
||||
|
||||
|
||||
UriResourceNavigationPropertyImpl navigationResource = new UriResourceNavigationPropertyImpl()
|
||||
.setNavigationProperty((EdmNavigationProperty) property);
|
||||
context.contextUriInfo.addResourcePart(navigationResource);
|
||||
|
@ -666,8 +675,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
// do a check for bound functions (which requires a parameter list)
|
||||
if (ctx.vlNVO.size() == 0) {
|
||||
throw wrap(new UriParserSemanticException("Unknown type for type cast " + fullFilterName.toString()
|
||||
+ " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE , fullFilterName.toString()));
|
||||
throw wrap(new UriParserSemanticException("Unknown type for type cast " + fullFilterName.toString()
|
||||
+ " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, fullFilterName.toString()));
|
||||
}
|
||||
|
||||
context.contextReadingFunctionParameters = true;
|
||||
|
@ -712,17 +721,17 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
UriParserSemanticException.MessageKeys.UNKNOWN_PART, fullFilterName.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that the namespace of the first resource parts is null
|
||||
* @param vNS namespace or null
|
||||
*/
|
||||
private void ensureNamespaceIsNull(final NamespaceContext vNS) {
|
||||
if(vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
|
||||
if (vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
|
||||
// First resource part and namespace is not null!
|
||||
throw wrap(new UriParserSemanticException("Namespace is not allowed for EntitySets, Singeltons, "
|
||||
+ " Action Imports and Function Imports. Found " + vNS.getText(),
|
||||
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, vNS.getText()));
|
||||
throw wrap(new UriParserSemanticException("Namespace is not allowed for EntitySets, Singeltons, "
|
||||
+ " Action Imports and Function Imports. Found " + vNS.getText(),
|
||||
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, vNS.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1138,22 +1147,22 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
UriInfoImpl crossJoin = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
|
||||
|
||||
for (OdataIdentifierContext obj : ctx.vlODI) {
|
||||
String odi = obj.getText();
|
||||
String odi = obj.getText();
|
||||
crossJoin.addEntitySetName(odi);
|
||||
|
||||
|
||||
EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
|
||||
if (edmEntitySet == null) {
|
||||
throw wrap(new UriParserSemanticException("Expected EntityTypeName",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));
|
||||
}
|
||||
|
||||
|
||||
EdmEntityType type = edmEntitySet.getEntityType();
|
||||
if (type == null) {
|
||||
throw wrap(new UriParserSemanticException("Expected EntityTypeName",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_ENTITY_TYPE, odi));
|
||||
}
|
||||
// contextUriInfo = uriInfo;
|
||||
context.contextTypes.push(new TypeInformation(type, true));
|
||||
context.contextTypes.push(new TypeInformation(type, true));
|
||||
}
|
||||
|
||||
context.contextUriInfo = crossJoin;
|
||||
|
@ -1237,10 +1246,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
levels.setText(ctx.vM.getText());
|
||||
try {
|
||||
expandItem.setSystemQueryOption(levels);
|
||||
} catch(ODataRuntimeException e) {
|
||||
} catch (ODataRuntimeException e) {
|
||||
// Thrown if duplicated system query options are detected
|
||||
throw wrap(new UriParserSyntaxException("Double system query option!", e,
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
}
|
||||
} else if (ctx.vL != null) {
|
||||
LevelsOptionImpl levels = new LevelsOptionImpl();
|
||||
|
@ -1249,10 +1258,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
levels.setValue(Integer.parseInt(text));
|
||||
try {
|
||||
expandItem.setSystemQueryOption(levels);
|
||||
} catch(ODataRuntimeException e) {
|
||||
} catch (ODataRuntimeException e) {
|
||||
// Thrown if duplicated system query options are detected
|
||||
throw wrap(new UriParserSyntaxException("Double system query option!", e,
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1269,10 +1278,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
for (SystemQueryOptionImpl option : list) {
|
||||
expandItem.setSystemQueryOption(option);
|
||||
}
|
||||
} catch(ODataRuntimeException e) {
|
||||
} catch (ODataRuntimeException e) {
|
||||
// Thrown if duplicated system query options are detected
|
||||
throw wrap(new UriParserSyntaxException("Double system query option!", e,
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
|
||||
}
|
||||
context.contextExpandItemPath = contextExpandItemPathBU;
|
||||
}
|
||||
|
@ -1293,11 +1302,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
// set tmp context
|
||||
context.contextExpandItemPath = expandItem;
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
|
||||
|
||||
|
||||
context.contextVisitExpandResourcePath = true;
|
||||
super.visitExpandPath(ctx);
|
||||
context.contextVisitExpandResourcePath = false;
|
||||
|
||||
|
||||
EdmType startType = removeUriResourceStartingTypeFilterImpl(context.contextUriInfo);
|
||||
expandItem.setResourcePath(context.contextUriInfo);
|
||||
if (startType != null) {
|
||||
|
@ -1400,14 +1409,22 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
@Override
|
||||
public Object visitFilter(final FilterContext ctx) {
|
||||
context.contextReadingQueryPart = true;
|
||||
final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2)
|
||||
.accept(this));
|
||||
context.contextReadingQueryPart = false;
|
||||
|
||||
return new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2).accept(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) {
|
||||
context.contextReadingQueryPart = true;
|
||||
final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0)
|
||||
.accept(this));
|
||||
context.contextReadingQueryPart = false;
|
||||
|
||||
return new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0).accept(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1614,7 +1631,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
|
||||
} else {
|
||||
// The functions returns a collection of entities
|
||||
// Get the EDM Type and determine how many key predicates are needed. In this case only one
|
||||
// Get the EDM Type and determine how many key predicates are needed. In this case only one
|
||||
// key predicate is allowed. If the entity type needs more than one key predicate, the client
|
||||
// has to use the key value syntax e.g. EntitySet(ID=1,Order=2)
|
||||
final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
|
||||
|
@ -1711,7 +1728,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
throw wrap(new UriParserSemanticException("Parameters list on untyped resource path segment not allowed",
|
||||
UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS));
|
||||
}
|
||||
if(last instanceof UriResourceFunction) {
|
||||
if (last instanceof UriResourceFunction) {
|
||||
final UriResourceFunction uriResourceFunction = (UriResourceFunction) context.contextUriInfo
|
||||
.getLastResourcePart();
|
||||
final EdmReturnType returnType = uriResourceFunction.getFunction().getReturnType();
|
||||
|
@ -1721,12 +1738,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
|
||||
} else {
|
||||
// The functions returns a collection of entities
|
||||
// Get the EDM Type and determine how many key predicates are needed.
|
||||
// Get the EDM Type and determine how many key predicates are needed.
|
||||
// In case of functions all key predicates must be provided by the client.
|
||||
final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
|
||||
final List<String> lastKeyPredicates = entityType.getKeyPredicateNames();
|
||||
|
||||
if(lastKeyPredicates.size() == list.size()) {
|
||||
|
||||
if (lastKeyPredicates.size() == list.size()) {
|
||||
return list;
|
||||
} else {
|
||||
throw wrap(new UriParserSemanticException("Wrong number of key properties.",
|
||||
|
@ -1737,15 +1754,15 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
} else {
|
||||
// Handle entity sets
|
||||
EdmEntityType lastType = (EdmEntityType) ((UriResourcePartTyped) last).getType();
|
||||
|
||||
|
||||
// get list of keys for lastType
|
||||
List<String> lastKeyPredicates = lastType.getKeyPredicateNames();
|
||||
|
||||
|
||||
// check if all key are filled from the URI
|
||||
if (list.size() == lastKeyPredicates.size()) {
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
// if not, check if the missing key predicates can be satisfied with help of the defined
|
||||
// referential constraints
|
||||
// for using referential constraints the last resource part must be a navigation property
|
||||
|
@ -1755,7 +1772,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
Integer.toString(lastKeyPredicates.size()), Integer.toString(list.size())));
|
||||
}
|
||||
UriResourceNavigationPropertyImpl lastNav = (UriResourceNavigationPropertyImpl) last;
|
||||
|
||||
|
||||
// get the partner of the navigation property
|
||||
EdmNavigationProperty partner = lastNav.getProperty().getPartner();
|
||||
if (partner == null) {
|
||||
|
@ -1763,7 +1780,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(lastKeyPredicates.size()), Integer.toString(list.size())));
|
||||
}
|
||||
|
||||
|
||||
// fill missing keys from referential constraints
|
||||
for (String key : lastKeyPredicates) {
|
||||
boolean found = false;
|
||||
|
@ -1773,7 +1790,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found) {
|
||||
String property = partner.getReferencingPropertyName(key);
|
||||
if (property != null) {
|
||||
|
@ -1782,7 +1799,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check again if all key predicates are filled from the URI
|
||||
if (list.size() == lastKeyPredicates.size()) {
|
||||
return list;
|
||||
|
@ -1794,7 +1811,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
}
|
||||
} else {
|
||||
// No key predicates are provided by the client
|
||||
|
||||
|
||||
if (context.contextReadingFunctionParameters) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
|
@ -1825,8 +1842,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
@Override
|
||||
public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) {
|
||||
return new LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).
|
||||
setText(ctx.getText());
|
||||
return new LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).setText(ctx
|
||||
.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1863,7 +1880,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
@Override
|
||||
public Object visitOrderByEOF(final OrderByEOFContext ctx) {
|
||||
|
||||
context.contextReadingQueryPart = true;
|
||||
|
||||
OrderByOptionImpl orderBy = new OrderByOptionImpl();
|
||||
|
||||
for (OrderByItemContext item : ((OrderListContext) ctx.getChild(0)).vlOI) {
|
||||
|
@ -1871,6 +1889,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
orderBy.addOrder(oItem);
|
||||
}
|
||||
|
||||
context.contextReadingFunctionParameters = false;
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
|
@ -1902,11 +1921,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
// check for keyPredicates
|
||||
if (pathInfoSegment instanceof UriResourceWithKeysImpl) {
|
||||
if (ctx.vlNVO.size() > 1) {
|
||||
throw wrap(new UriParserSemanticException("More than one key predicates found",
|
||||
throw wrap(new UriParserSemanticException("More than one key predicates found",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES, "1",
|
||||
Integer.toString(ctx.vlNVO.size())));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<UriParameterImpl> list = (List<UriParameterImpl>) ctx.vlNVO.get(0).accept(this);
|
||||
((UriResourceWithKeysImpl) pathInfoSegment)
|
||||
|
@ -1937,7 +1956,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
@Override
|
||||
public Object visitPrimitiveLiteral(final PrimitiveLiteralContext ctx) {
|
||||
ParseTree child1 = ctx.children.get(0);
|
||||
|
||||
|
||||
if (child1 instanceof EnumLiteralContext
|
||||
|| child1 instanceof BooleanNonCaseLiteralContext
|
||||
|| child1 instanceof NullruleLiteralContext
|
||||
|
@ -1954,11 +1973,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|| child1 instanceof BinaryLiteralContext) {
|
||||
return child1.accept(this);
|
||||
}
|
||||
|
||||
// TODO Implement geography types and set the proper type
|
||||
|
||||
// TODO Implement geography types and set a proper type
|
||||
return new LiteralImpl().setText(ctx.getText());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visitBinaryLiteral(BinaryLiteralContext ctx) {
|
||||
return new LiteralImpl().setText(ctx.getText())
|
||||
|
@ -1968,14 +1987,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
@Override
|
||||
public Object visitStringLiteral(final StringLiteralContext ctx) {
|
||||
return new LiteralImpl().setText(ctx.getText())
|
||||
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
|
||||
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visitDecimalLiteral(final DecimalLiteralContext ctx) {
|
||||
final EdmType type = EdmPrimitiveTypeFactory.getInstance(
|
||||
ctx.getText().contains("e") || ctx.getText().contains("E") ?
|
||||
EdmPrimitiveTypeKind.Double : EdmPrimitiveTypeKind.Decimal);
|
||||
ctx.getText().contains("e") || ctx.getText().contains("E") ? EdmPrimitiveTypeKind.Double
|
||||
: EdmPrimitiveTypeKind.Decimal);
|
||||
|
||||
return new LiteralImpl().setText(ctx.getText()).setType(type);
|
||||
}
|
||||
|
@ -1999,7 +2018,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
}
|
||||
|
||||
return new LiteralImpl().setText(ctx.getText()).setType(type);
|
||||
} catch( NumberFormatException e) {
|
||||
} catch (NumberFormatException e) {
|
||||
return new LiteralImpl().setText(ctx.getText())
|
||||
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
|
||||
}
|
||||
|
@ -2012,7 +2031,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitDatetimeoffsetLiteral(final DatetimeoffsetLiteralContext ctx) {
|
||||
public Object visitDatetimeoffsetLiteral(final DatetimeoffsetLiteralContext ctx) {
|
||||
return new LiteralImpl().setText(ctx.getText())
|
||||
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset));
|
||||
}
|
||||
|
@ -2124,13 +2143,17 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
|
||||
@Override
|
||||
public Object visitSelectEOF(final SelectEOFContext ctx) {
|
||||
context.contextReadingQueryPart = true;
|
||||
List<SelectItemImpl> selectItems = new ArrayList<SelectItemImpl>();
|
||||
|
||||
for (SelectItemContext si : ctx.vlSI) {
|
||||
selectItems.add((SelectItemImpl) si.accept(this));
|
||||
}
|
||||
|
||||
return new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
|
||||
final QueryOptionImpl result = new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
|
||||
context.contextReadingQueryPart = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2492,10 +2515,29 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
|||
alias.setParameter("@" + ctx.odataIdentifier().getChild(0).getText());
|
||||
return alias;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visitSearchSpecialToken(final SearchSpecialTokenContext ctx) {
|
||||
throw wrap(new UriParserSemanticException("System query option '$search' not implemented!",
|
||||
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query option '$search"));
|
||||
throw wrap(new UriParserSemanticException("System query option '$search' not implemented!",
|
||||
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query option '$search"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitArrayOrObject(final ArrayOrObjectContext ctx) {
|
||||
if (!context.contextReadingQueryPart) {
|
||||
throw wrap(new UriParserSemanticException("Complex parameter are not allowed in resource path",
|
||||
MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, ctx.getText()));
|
||||
}
|
||||
|
||||
return new LiteralImpl().setText(ctx.getText()).setType(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitExpandItemsEOF(ExpandItemsEOFContext ctx) {
|
||||
context.contextReadingQueryPart = true;
|
||||
final Object result = super.visitExpandItemsEOF(ctx);
|
||||
context.contextReadingQueryPart = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,11 @@ public class UriParserSemanticException extends UriParserException {
|
|||
/** parameter: not implemented part */
|
||||
NOT_IMPLEMENTED,
|
||||
/** parameter: namespace **/
|
||||
NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT;
|
||||
NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT,
|
||||
/** parameter: complex parameter value */
|
||||
COMPLEX_PARAMETER_IN_RESOURCE_PATH,
|
||||
/** parameter: function import name */
|
||||
FUNCTION_IMPORT_NOT_ALLOWED;
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
|
|
|
@ -35,7 +35,9 @@ public class UriParserSyntaxException extends UriParserException {
|
|||
/** parameter: $format option value */
|
||||
WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT,
|
||||
SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE,
|
||||
SYNTAX;
|
||||
SYNTAX,
|
||||
/** parameter: alias name */
|
||||
DUPLICATED_ALIAS;
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
|
|
|
@ -37,6 +37,8 @@ public class UriValidationException extends ODataLibraryException {
|
|||
UNSUPPORTED_ACTION_RETURN_TYPE,
|
||||
/** parameter: unsupported http method */
|
||||
UNSUPPORTED_HTTP_METHOD,
|
||||
/** parameter: unsupported parameter name */
|
||||
UNSUPPORTED_PARAMETER,
|
||||
/** parameter: system query option */
|
||||
SYSTEM_QUERY_OPTION_NOT_ALLOWED,
|
||||
/** parameters: system query option, http method */
|
||||
|
@ -54,8 +56,11 @@ public class UriValidationException extends ODataLibraryException {
|
|||
/** parameter: unallowed kind before $count */
|
||||
UNALLOWED_KIND_BEFORE_COUNT,
|
||||
/** parameter: unallowed resource path */
|
||||
UNALLOWED_RESOURCE_PATH;
|
||||
UNALLOWED_RESOURCE_PATH,
|
||||
/** parameter: missing parameter name */
|
||||
MISSING_PARAMETER;
|
||||
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return name();
|
||||
|
|
|
@ -139,6 +139,7 @@ public class UriValidator {
|
|||
validateForHttpMethod(uriInfo, httpMethod);
|
||||
}
|
||||
validateQueryOptions(uriInfo);
|
||||
validateParameters(uriInfo);
|
||||
validateKeyPredicates(uriInfo);
|
||||
validatePropertyOperations(uriInfo, httpMethod);
|
||||
}
|
||||
|
@ -556,6 +557,58 @@ public class UriValidator {
|
|||
return UriResourceKind.action == uriResourceParts.get(uriResourceParts.size() - 1).getKind();
|
||||
}
|
||||
|
||||
private void validateParameters(final UriInfo uriInfo) throws UriValidationException {
|
||||
for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
|
||||
final boolean isFunction = pathSegment.getKind() == UriResourceKind.function;
|
||||
|
||||
if(isFunction) {
|
||||
final UriResourceFunction functionPathSegement = (UriResourceFunction) pathSegment;
|
||||
final EdmFunction edmFuntion = functionPathSegement.getFunction();
|
||||
|
||||
final Map<String, UriParameter> parameters = new HashMap<String, UriParameter>();
|
||||
for(final UriParameter parameter : functionPathSegement.getParameters()) {
|
||||
parameters.put(parameter.getName(), parameter);
|
||||
}
|
||||
|
||||
boolean firstParameter = true;
|
||||
for(final String parameterName : edmFuntion.getParameterNames()) {
|
||||
final UriParameter parameter = parameters.get(parameterName);
|
||||
final boolean isNullable = edmFuntion.getParameter(parameterName).isNullable();
|
||||
|
||||
if(parameter != null) {
|
||||
/** No alias, value explicit null */
|
||||
if(parameter.getText() == null
|
||||
&& parameter.getAlias() == null && !isNullable) {
|
||||
throw new UriValidationException("Missing non nullable parameter " + parameterName,
|
||||
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
|
||||
} else if(parameter.getText() == null && parameter.getAlias() != null) {
|
||||
final String valueForAlias = uriInfo.getValueForAlias(parameter.getAlias());
|
||||
/** Alias value is missing or explicit null **/
|
||||
if(valueForAlias == null && !isNullable) {
|
||||
throw new UriValidationException("Missing non nullable parameter " + parameterName,
|
||||
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
parameters.remove(parameterName);
|
||||
} else if(!isNullable && !(firstParameter && edmFuntion.isBound())) {
|
||||
// The first parameter of bound functions is implicit provided by the preceding path segment
|
||||
throw new UriValidationException("Missing non nullable parameter " + parameterName,
|
||||
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
|
||||
}
|
||||
|
||||
firstParameter = false;
|
||||
}
|
||||
|
||||
if(!parameters.isEmpty()) {
|
||||
final String parameterName = parameters.keySet().iterator().next();
|
||||
throw new UriValidationException("Unsupported parameter " + parameterName,
|
||||
UriValidationException.MessageKeys.UNSUPPORTED_PARAMETER, parameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateKeyPredicates(final UriInfo uriInfo) throws UriValidationException {
|
||||
for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
|
||||
final boolean isEntitySet = pathSegment.getKind() == UriResourceKind.entitySet;
|
||||
|
|
|
@ -35,6 +35,7 @@ UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION=The system query op
|
|||
UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT=The system query option '$format' must be either 'json', 'xml', 'atom', or a valid content type; the value '%1$s' is neither.
|
||||
UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here.
|
||||
UriParserSyntaxException.SYNTAX=The URI is malformed.
|
||||
UriParserSyntaxException.DUPLICATED_ALIAS=Duplicated alias. An alias '%1$s' was already specified!.
|
||||
|
||||
UriParserSemanticException.FUNCTION_NOT_FOUND=The function import '%1$s' has no function with parameters '%2$s'.
|
||||
UriParserSemanticException.RESOURCE_PART_ONLY_FOR_TYPED_PARTS='%1$s' is only allowed for typed parts.
|
||||
|
@ -68,6 +69,8 @@ UriParserSemanticException.PREVIOUS_PART_TYPED=The previous part is typed.
|
|||
UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'.
|
||||
UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
|
||||
UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'.
|
||||
UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments. Found: '%1$s'.
|
||||
UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are not allowed in $filter or $orderby. Found: '%1$s'.
|
||||
|
||||
UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported.
|
||||
UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported.
|
||||
|
@ -75,6 +78,7 @@ UriValidationException.UNSUPPORTED_URI_RESOURCE_KIND=The URI resource kind '%1$s
|
|||
UriValidationException.UNSUPPORTED_FUNCTION_RETURN_TYPE=The function return type '%1$s' is not supported.
|
||||
UriValidationException.UNSUPPORTED_ACTION_RETURN_TYPE=The action return type '%1$s' is not supported.
|
||||
UriValidationException.UNSUPPORTED_HTTP_METHOD=The HTTP method '%1$s' is not supported.
|
||||
UriValidationException.UNSUPPORTED_PARAMETER=The parameter '%1$s' is not supported.
|
||||
UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED=The system query option '%1$s' is not allowed.
|
||||
UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD=The system query option '%1$s' is not allowed for HTTP method '%2$s'.
|
||||
UriValidationException.INVALID_KEY_PROPERTY=The key property '%1$s' is invalid.
|
||||
|
@ -84,6 +88,7 @@ UriValidationException.SECOND_LAST_SEGMENT_NOT_TYPED=The second last segment '%1
|
|||
UriValidationException.UNALLOWED_KIND_BEFORE_VALUE=The kind '%1$s' is not allowed before '$value'.
|
||||
UriValidationException.UNALLOWED_KIND_BEFORE_COUNT=The kind '%1$s' is not allowed before '$count'.
|
||||
UriValidationException.UNALLOWED_RESOURCE_PATH=The resource part '%1$s' is not allowed.
|
||||
UriValidationException.MISSING_PARAMETER=Missing mandatory parameter '%1$s'.
|
||||
|
||||
ContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range '%1$s' is not supported as value of the Accept header.
|
||||
ContentNegotiatorException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported.
|
||||
|
|
|
@ -2036,7 +2036,8 @@ public class TestFullResourcePath {
|
|||
|
||||
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)", "@parameterAlias=1");
|
||||
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count", "@parameterAlias=1");
|
||||
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", "@validAlias=1");
|
||||
testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", "@validAlias=1")
|
||||
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -5658,7 +5659,94 @@ public class TestFullResourcePath {
|
|||
.root()
|
||||
.right().isLiteral("" + Long.MAX_VALUE).isLiteralType(EdmInt64.getInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterAliasLiteralValidation() throws Exception {
|
||||
testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=1");
|
||||
testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=-2");
|
||||
testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe'")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functionsWithComplexParameters() throws Exception {
|
||||
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}")
|
||||
.goPath()
|
||||
.at(0).isEntitySet("ESTwoKeyNav")
|
||||
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
|
||||
|
||||
// Test JSON String lexer rule =\"3,Int16=abc},\\\nabc&test%test\b\f\r\t\u0022}
|
||||
final String stringValueEncoded = "=\\\"3,Int16=abc},\\\\\\nabc%26test%25test\\b\\f\\r\\t\\u0022}";
|
||||
final String stringValueDecoded = "=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}";
|
||||
|
||||
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueEncoded + "\"}")
|
||||
.goPath()
|
||||
.at(0).isEntitySet("ESTwoKeyNav")
|
||||
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueDecoded + "\"}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) eq 'Test'")
|
||||
.goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
|
||||
.isParameterText(0, "{\"PropertyString\":\"Test\",\"PropertyInt16\":1}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp={\"PropertyString\":\"" + stringValueEncoded + "\",\"PropertyInt16\":1}) eq 'Test'")
|
||||
.goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
|
||||
.isParameterText(0, "{\"PropertyString\":\"=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}\","
|
||||
+ "\"PropertyInt16\":1}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
|
||||
|
||||
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":'1'}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
|
||||
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)")
|
||||
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null")
|
||||
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
|
||||
|
||||
testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test, UnknownParam=1)", "@test='null'")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
|
||||
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null");
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)");
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)");
|
||||
|
||||
testUri.runEx("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null&@test='1'")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
|
||||
|
||||
testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Key predicates in filter/orderby expression are not validated currently")
|
||||
public void testKeyPredicatesInExpressions() throws Exception {
|
||||
testUri.run("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(PropertyString='1',PropertyInt16=1)"
|
||||
+ "/PropertyInt16 eq 1");
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(Prop='22',P=2)/PropertyInt16 eq 0")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
}
|
||||
|
||||
public static String encode(final String decoded) throws UnsupportedEncodingException {
|
||||
return Encoder.encode(decoded);
|
||||
}
|
||||
|
|
|
@ -1061,7 +1061,7 @@ public class TestUriParserImpl {
|
|||
|
||||
@Test
|
||||
public void testAlias() throws Exception {
|
||||
testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1)")
|
||||
testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1")
|
||||
.goFilter().is("<<PropertyInt16> eq <@p1>>");
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
|||
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
|
||||
|
@ -68,7 +69,7 @@ public class EdmTechTestProvider extends EdmTechProvider {
|
|||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
return super.getComplexType(complexTypeName);
|
||||
}
|
||||
|
||||
|
@ -115,5 +116,13 @@ public class EdmTechTestProvider extends EdmTechProvider {
|
|||
|
||||
return super.getEntityType(entityTypeName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CsdlFunctionImport getFunctionImport(FullQualifiedName entityContainer, String functionImportName)
|
||||
throws ODataException {
|
||||
|
||||
|
||||
return super.getFunctionImport(entityContainer, functionImportName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,12 +31,14 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
|||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
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;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.Member;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
|
||||
import org.apache.olingo.server.core.uri.UriInfoImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
|
@ -403,16 +405,26 @@ public class FilterValidator implements TestValidator {
|
|||
public FilterValidator isParameterText(final int parameterIndex, final String parameterText)
|
||||
throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
if (!(curExpression instanceof MethodImpl)) {
|
||||
fail("Current expression is not a method");
|
||||
if (curExpression instanceof MethodImpl) {
|
||||
MethodImpl methodCall = (MethodImpl) curExpression;
|
||||
|
||||
Expression parameter = methodCall.getParameters().get(parameterIndex);
|
||||
String actualParameterText = FilterTreeToText.Serialize(parameter);
|
||||
assertEquals(parameterText, actualParameterText);
|
||||
} else if (curExpression instanceof MemberImpl) {
|
||||
final MemberImpl member = (MemberImpl) curExpression;
|
||||
final List<UriResource> uriResourceParts = member.getResourcePath().getUriResourceParts();
|
||||
|
||||
if (!uriResourceParts.isEmpty() && uriResourceParts.get(0) instanceof UriResourceFunctionImpl) {
|
||||
assertEquals(parameterText, ((UriResourceFunctionImpl) uriResourceParts.get(0)).getParameters()
|
||||
.get(parameterIndex).getText());
|
||||
} else {
|
||||
fail("Current expression is not a method or function");
|
||||
}
|
||||
} else {
|
||||
fail("Current expression is not a method or function");
|
||||
}
|
||||
|
||||
MethodImpl methodCall = (MethodImpl) curExpression;
|
||||
|
||||
Expression parameter = methodCall.getParameters().get(parameterIndex);
|
||||
String actualParameterText = FilterTreeToText.Serialize(parameter);
|
||||
assertEquals(parameterText, actualParameterText);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue