[OLINGO-194] complex and collection literals + URI escape tests
This commit is contained in:
parent
7651350846
commit
3e53ac5b7d
|
@ -153,7 +153,7 @@ public class ODataInvokeRequestImpl<T extends ODataInvokeResult>
|
|||
throw new IllegalArgumentException("Only primitive values can be passed via GET");
|
||||
}
|
||||
|
||||
uriBuilder.addParameter(param.getKey(), param.getValue().toString());
|
||||
uriBuilder.addParameter(param.getKey(), URIUtils.escape(odataClient.getServiceVersion(), param.getValue()));
|
||||
}
|
||||
try {
|
||||
((HttpRequestBase) this.request).setURI(uriBuilder.build());
|
||||
|
|
|
@ -27,7 +27,11 @@ import java.net.URI;
|
|||
import java.net.URLEncoder;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.xml.datatype.Duration;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -67,6 +71,8 @@ public final class URIUtils {
|
|||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(URIUtils.class);
|
||||
|
||||
private static final Pattern ENUM_VALUE = Pattern.compile("(.+\\.)?.+'.+'");
|
||||
|
||||
private URIUtils() {
|
||||
// Empty private constructor for static utility classes
|
||||
}
|
||||
|
@ -274,53 +280,102 @@ public final class URIUtils {
|
|||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null), Constants.UTF8));
|
||||
}
|
||||
|
||||
private static String quoteString(final String string, final boolean singleQuoteEscape)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
final String encoded = URLEncoder.encode(string, Constants.UTF8);
|
||||
return ENUM_VALUE.matcher(string).matches()
|
||||
? encoded
|
||||
: singleQuoteEscape
|
||||
? "'" + encoded + "'"
|
||||
: "\"" + encoded + "\"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns primitive values into their respective URI representation.
|
||||
*
|
||||
* @param version OData protocol version
|
||||
* @param obj primitive value
|
||||
* @return URI representation
|
||||
*/
|
||||
public static String escape(final ODataServiceVersion version, final Object obj) {
|
||||
return escape(version, obj, true);
|
||||
}
|
||||
|
||||
private static String escape(final ODataServiceVersion version, final Object obj, final boolean singleQuoteEscape) {
|
||||
String value;
|
||||
|
||||
try {
|
||||
value = (obj instanceof Boolean)
|
||||
? BooleanUtils.toStringTrueFalse((Boolean) obj)
|
||||
: (obj instanceof UUID)
|
||||
? prefix(version, EdmPrimitiveTypeKind.Guid)
|
||||
+ obj.toString()
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Guid)
|
||||
: (obj instanceof byte[])
|
||||
? EdmBinary.getInstance().toUriLiteral(Hex.encodeHexString((byte[]) obj))
|
||||
: (obj instanceof Timestamp)
|
||||
? timestamp(version, (Timestamp) obj)
|
||||
: (obj instanceof Calendar)
|
||||
? calendar(version, (Calendar) obj)
|
||||
: (obj instanceof Duration)
|
||||
? duration(version, (Duration) obj)
|
||||
: (obj instanceof BigDecimal)
|
||||
? EdmDecimal.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Decimal)
|
||||
: (obj instanceof Double)
|
||||
? EdmDouble.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Double)
|
||||
: (obj instanceof Float)
|
||||
? EdmSingle.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Single)
|
||||
: (obj instanceof Long)
|
||||
? EdmInt64.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Int64)
|
||||
: (obj instanceof Geospatial)
|
||||
? URLEncoder.encode(EdmPrimitiveTypeFactory.getInstance(((Geospatial) obj).getEdmPrimitiveTypeKind()).
|
||||
valueToString(obj, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
|
||||
Constants.UTF8)
|
||||
: (obj instanceof String)
|
||||
? "'" + URLEncoder.encode((String) obj, Constants.UTF8) + "'"
|
||||
: obj.toString();
|
||||
if (obj == null) {
|
||||
value = Constants.ATTR_NULL;
|
||||
} else if (version == ODataServiceVersion.V40 && obj instanceof Collection) {
|
||||
final StringBuffer buffer = new StringBuffer("[");
|
||||
for (@SuppressWarnings("unchecked")
|
||||
final Iterator<Object> itor = ((Collection<Object>) obj).iterator(); itor.hasNext();) {
|
||||
buffer.append(escape(version, itor.next(), false));
|
||||
if (itor.hasNext()) {
|
||||
buffer.append(',');
|
||||
}
|
||||
}
|
||||
buffer.append(']');
|
||||
|
||||
value = buffer.toString();
|
||||
} else if (version == ODataServiceVersion.V40 && obj instanceof Map) {
|
||||
final StringBuffer buffer = new StringBuffer("{");
|
||||
for (@SuppressWarnings("unchecked")
|
||||
final Iterator<Map.Entry<Object, Object>> itor =
|
||||
((Map<Object, Object>) obj).entrySet().iterator(); itor.hasNext();) {
|
||||
|
||||
final Map.Entry<Object, Object> entry = itor.next();
|
||||
buffer.append("\"").append(URLEncoder.encode(entry.getKey().toString(), Constants.UTF8)).append("\"");
|
||||
buffer.append(':').append(escape(version, entry.getValue(), false));
|
||||
|
||||
if (itor.hasNext()) {
|
||||
buffer.append(',');
|
||||
}
|
||||
}
|
||||
buffer.append('}');
|
||||
|
||||
value = buffer.toString();
|
||||
} else {
|
||||
value = (obj instanceof Boolean)
|
||||
? BooleanUtils.toStringTrueFalse((Boolean) obj)
|
||||
: (obj instanceof UUID)
|
||||
? prefix(version, EdmPrimitiveTypeKind.Guid)
|
||||
+ obj.toString()
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Guid)
|
||||
: (obj instanceof byte[])
|
||||
? EdmBinary.getInstance().toUriLiteral(Hex.encodeHexString((byte[]) obj))
|
||||
: (obj instanceof Timestamp)
|
||||
? timestamp(version, (Timestamp) obj)
|
||||
: (obj instanceof Calendar)
|
||||
? calendar(version, (Calendar) obj)
|
||||
: (obj instanceof Duration)
|
||||
? duration(version, (Duration) obj)
|
||||
: (obj instanceof BigDecimal)
|
||||
? EdmDecimal.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Decimal)
|
||||
: (obj instanceof Double)
|
||||
? EdmDouble.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Double)
|
||||
: (obj instanceof Float)
|
||||
? EdmSingle.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Single)
|
||||
: (obj instanceof Long)
|
||||
? EdmInt64.getInstance().valueToString(obj, null, null,
|
||||
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
|
||||
+ suffix(version, EdmPrimitiveTypeKind.Int64)
|
||||
: (obj instanceof Geospatial)
|
||||
? URLEncoder.encode(EdmPrimitiveTypeFactory.getInstance(((Geospatial) obj).getEdmPrimitiveTypeKind()).
|
||||
valueToString(obj, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
|
||||
Constants.UTF8)
|
||||
: (obj instanceof String)
|
||||
? quoteString((String) obj, singleQuoteEscape)
|
||||
: obj.toString();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("While escaping '{}', using toString()", obj, e);
|
||||
value = obj.toString();
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
package org.apache.olingo.client.core.uri;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.apache.olingo.client.core.edm.EdmEnumTypeImpl;
|
||||
import org.apache.olingo.client.core.edm.xml.v4.EnumTypeImpl;
|
||||
import org.apache.olingo.commons.api.Constants;
|
||||
import org.apache.olingo.commons.api.edm.EdmEnumType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
|
||||
import org.apache.olingo.commons.api.edm.geo.Geospatial;
|
||||
import org.apache.olingo.commons.api.edm.geo.Point;
|
||||
import org.junit.Test;
|
||||
|
||||
public class URIEscapeTest {
|
||||
|
||||
@Test
|
||||
public void _null() {
|
||||
assertEquals("null", URIUtils.escape(ODataServiceVersion.V40, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void _boolean() {
|
||||
assertEquals("true", URIUtils.escape(ODataServiceVersion.V40, Boolean.TRUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void _enum() throws UnsupportedEncodingException {
|
||||
final EdmEnumType pattern = new EdmEnumTypeImpl(ODataServiceVersion.V40,
|
||||
null, new FullQualifiedName("Sales", "Pattern"), new EnumTypeImpl());
|
||||
|
||||
assertEquals(URLEncoder.encode("Sales.Pattern'Yellow'", Constants.UTF8),
|
||||
URIUtils.escape(ODataServiceVersion.V40, pattern.toUriLiteral("Yellow")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void geospatial() throws UnsupportedEncodingException {
|
||||
final Point point = new Point(Geospatial.Dimension.GEOGRAPHY, 0);
|
||||
point.setX(142.1);
|
||||
point.setY(64.1);
|
||||
|
||||
assertEquals(URLEncoder.encode("geography'SRID=0;Point(142.1 64.1)'", Constants.UTF8),
|
||||
URIUtils.escape(ODataServiceVersion.V40, point));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collection() {
|
||||
assertEquals("[\"red\",\"green\"]",
|
||||
URIUtils.escape(ODataServiceVersion.V40, Arrays.asList(new String[] {"red", "green"})));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complex() {
|
||||
assertEquals("{\"Name\":\"Value\"}",
|
||||
URIUtils.escape(ODataServiceVersion.V40, Collections.singletonMap("Name", "Value")));
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.client.core.v3;
|
||||
package org.apache.olingo.client.core.uri.v3;
|
||||
|
||||
import org.apache.olingo.client.api.v3.ODataClient;
|
||||
import org.apache.olingo.client.api.uri.URIFilter;
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.client.core.v3;
|
||||
package org.apache.olingo.client.core.uri.v3;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.client.core.v4;
|
||||
package org.apache.olingo.client.core.uri.v4;
|
||||
|
||||
import org.apache.olingo.client.api.v4.ODataClient;
|
||||
import org.apache.olingo.client.api.uri.URIFilter;
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.client.core.v4;
|
||||
package org.apache.olingo.client.core.uri.v4;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
Loading…
Reference in New Issue