Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
670c71c
bug fix: error code and message not parsed. e.g or raw response:
Oct 13, 2020
6d292e2
bug fix: null pointer exception on parsing a null value for enum type,
Nov 2, 2020
029952f
bug fix: EdmPropertyImpl is throwing EdmException "Cannot find type with
Nov 2, 2020
762736e
bug fix: missed typeDefinition in the previous bug fix
Nov 2, 2020
b85510d
supressing nonsense exceptions
Mar 18, 2021
73d10a7
commented out buggy plugin
Mar 18, 2021
bde0752
test
Mar 18, 2021
04a36e4
test
Mar 18, 2021
66da9c9
Update EdmAnnotation.java
iegoshin Feb 23, 2022
ae4bf9d
Update EdmAnnotationImpl.java
iegoshin Feb 23, 2022
a902d4b
ignore missing @odata.nextLink;
iegoshin Nov 19, 2024
6db925c
test
iegoshin Nov 19, 2024
601cf3f
test
iegoshin Nov 19, 2024
926ce7f
bug fix for nested value: "@odata.associationLink": {
iegoshin Apr 3, 2025
7d48558
fixing broken nextLink
iegoshin May 23, 2025
4f4a9d6
source format fix
iegoshin May 23, 2025
97e2e06
url normalization
iegoshin May 23, 2025
8b8b05d
bug fix: anchor is missing in URL
iegoshin May 26, 2025
e86563f
small fix for EdmBoolean
iegoshin Aug 21, 2025
32ae8bf
bug fix: exception on empty value for timestamp field
iegoshin Aug 21, 2025
33a0b0b
allow to parse just date without the time and zone
iegoshin Aug 21, 2025
8cc89d7
helper methods for Property Searchable annotations
iegoshin Mar 27, 2026
b3be1b0
helper methods added
iegoshin Mar 27, 2026
969afaf
helper method added
iegoshin Mar 27, 2026
c1f4583
bug fix: null lookup name
iegoshin Mar 27, 2026
4099c2a
style
iegoshin Mar 27, 2026
e321ba4
searchable should return 3 values: true, false and null
iegoshin Mar 27, 2026
ddc60fc
trim leading and trailing spaces from labels
iegoshin Mar 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/client-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<parent>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-lib</artifactId>
<version>4.8.0-SNAPSHOT</version>
<version>4.8.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion lib/client-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<parent>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-lib</artifactId>
<version>4.8.0-SNAPSHOT</version>
<version>4.8.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public BuilderImpl setType(final EdmType type) {

@Override
public BuilderImpl setType(final EdmPrimitiveTypeKind type) {
if (type == EdmPrimitiveTypeKind.Stream) {
// Ilya: throwing these exceptions from here doesn't make sense
/*if (type == EdmPrimitiveTypeKind.Stream) {
throw new IllegalArgumentException(String.format(
"Cannot build a primitive value for %s", EdmPrimitiveTypeKind.Stream.toString()));
}
Expand All @@ -66,7 +67,7 @@ public BuilderImpl setType(final EdmPrimitiveTypeKind type) {
+ "An entity can declare a property to be of type Geometry. "
+ "An instance of an entity MUST NOT have a value of type Geometry. "
+ "Each value MUST be of some subtype.");
}
}*/

instance.typeKind = type == null ? EdmPrimitiveTypeKind.String : type;
instance.type = EdmPrimitiveTypeFactory.getInstance(instance.typeKind);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,17 @@ private void clientLinks(final Map.Entry<String, JsonNode> field, final Linked l
final Link link = new Link();
link.setTitle(getTitle(field));
link.setRel(Constants.NS_ASSOCIATION_LINK_REL + getTitle(field));
link.setHref(field.getValue().textValue());
if (field.getValue() instanceof ObjectNode) {
ObjectNode values = (ObjectNode)field.getValue();
JsonNode value = values.findValue(Constants.JSON_ASSOCIATION_LINK);
if (value!=null) {
link.setHref(value.textValue());
} else {
link.setHref(field.getValue().textValue());
}
} else {
link.setHref(field.getValue().textValue());
}
link.setType(Constants.ASSOCIATION_LINK_TYPE);
linked.getAssociationLinks().add(link);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
Expand Down Expand Up @@ -60,16 +63,16 @@ protected ResWrap<EntityCollection> doDeserialize(final JsonParser parser) throw

URI contextURL;
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
contextURL = URI.create(tree.get(Constants.JSON_CONTEXT).textValue());
contextURL = getUri(tree.get(Constants.JSON_CONTEXT).textValue());
tree.remove(Constants.JSON_CONTEXT);
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
contextURL = URI.create(tree.get(Constants.JSON_METADATA).textValue());
contextURL = getUri(tree.get(Constants.JSON_METADATA).textValue());
tree.remove(Constants.JSON_METADATA);
} else {
contextURL = null;
}
if (contextURL != null) {
entitySet.setBaseURI(URI.create(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA)));
entitySet.setBaseURI(getUri(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA)));
}

final String metadataETag;
Expand All @@ -85,11 +88,11 @@ protected ResWrap<EntityCollection> doDeserialize(final JsonParser parser) throw
tree.remove(Constants.JSON_COUNT);
}
if (tree.hasNonNull(Constants.JSON_NEXT_LINK)) {
entitySet.setNext(URI.create(tree.get(Constants.JSON_NEXT_LINK).textValue()));
entitySet.setNext(getUri(tree.get(Constants.JSON_NEXT_LINK).textValue()));
tree.remove(Constants.JSON_NEXT_LINK);
}
if (tree.hasNonNull(Constants.JSON_DELTA_LINK)) {
entitySet.setDeltaLink(URI.create(tree.get(Constants.JSON_DELTA_LINK).textValue()));
entitySet.setDeltaLink(getUri(tree.get(Constants.JSON_DELTA_LINK).textValue()));
tree.remove(Constants.JSON_DELTA_LINK);
}

Expand Down Expand Up @@ -121,12 +124,68 @@ protected ResWrap<EntityCollection> doDeserialize(final JsonParser parser) throw

final ObjectNode opNode = (ObjectNode) tree.get(field.getKey());
operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText());
operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText()));
operation.setTarget(getUri(opNode.get(Constants.ATTR_TARGET).asText()));
entitySet.getOperations().add(operation);
toRemove.add(field.getKey());
}
}
tree.remove(toRemove);
return new ResWrap<>(contextURL, metadataETag, entitySet);
}

private URI getUri(String str) throws IOException {
try {
URL url = new URL(str);
String scheme = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
String path = url.getPath();
String baseUrl = scheme + "://" + host + (port != -1 ? ":" + port : "") + path;
String query = url.getQuery();
String anchor = StringUtils.substringAfterLast(str, "#");

if (query == null || query.isEmpty()) {
return URI.create(str);
}

StringBuilder fixedQuery = new StringBuilder();
for (String param : query.split("&")) {
int idx = param.indexOf('=');
if (idx > 0) {
String key = param.substring(0, idx);
String value = param.substring(idx + 1);

key = URLDecoder.decode(key, "UTF-8");
value = URLDecoder.decode(value, "UTF-8");

if (!key.startsWith("$")) {
key = "$" + key;
}

String encodedKey = URLEncoder.encode(key, "UTF-8").replace("+", "%20");
String encodedValue = URLEncoder.encode(value, "UTF-8").replace("+", "%20");

if (fixedQuery.length() > 0) {
fixedQuery.append("&");
}

fixedQuery.append(encodedKey).append("=").append(encodedValue);
} else {
String decoded = URLDecoder.decode(param, "UTF-8");
fixedQuery.append(URLEncoder.encode(decoded, "UTF-8").replace("+", "%20"));
}
}

if (StringUtils.isNotBlank(anchor)) {
anchor = URLDecoder.decode(anchor, "UTF-8");
String encodedAnchor = URLEncoder.encode(anchor, "UTF-8").replace("+", "%20");
fixedQuery.append("#").append(encodedAnchor);
}

return new URI(baseUrl + "?" + fixedQuery);

} catch (Exception e) {
throw new IOException("Failed to normalize URI: " + str, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,54 +34,91 @@

public class JsonODataErrorDeserializer extends JsonDeserializer {

public JsonODataErrorDeserializer(final boolean serverMode) {
super(serverMode);
}
public JsonODataErrorDeserializer(final boolean serverMode) {
super(serverMode);
}

protected ODataError doDeserialize(final JsonParser parser) throws IOException {
protected ODataError doDeserialize(final JsonParser parser) throws IOException {

final ODataError error = new ODataError();
final ODataError error = new ODataError();

final ObjectNode tree = parser.getCodec().readTree(parser);
if (tree.has(Constants.JSON_ERROR)) {
final JsonNode errorNode = tree.get(Constants.JSON_ERROR);
final ObjectNode tree = parser.getCodec().readTree(parser);
if (tree.has(Constants.JSON_ERROR)) {
final JsonNode errorNode = tree.get(Constants.JSON_ERROR);

if (errorNode.has(Constants.ERROR_CODE)) {
error.setCode(errorNode.get(Constants.ERROR_CODE).textValue());
}
if (errorNode.has(Constants.ERROR_MESSAGE)) {
final JsonNode message = errorNode.get(Constants.ERROR_MESSAGE);
if (message.isValueNode()) {
error.setMessage(message.textValue());
} else if (message.isObject()) {
error.setMessage(message.get(Constants.VALUE).asText());
}
}
if (errorNode.has(Constants.ERROR_TARGET)) {
error.setTarget(errorNode.get(Constants.ERROR_TARGET).textValue());
}
if (errorNode.hasNonNull(Constants.ERROR_DETAILS)) {
List<ODataErrorDetail> details = new ArrayList<>();
JsonODataErrorDetailDeserializer detailDeserializer = new JsonODataErrorDetailDeserializer(serverMode);
for (JsonNode jsonNode : errorNode.get(Constants.ERROR_DETAILS)) {
details.add(detailDeserializer.doDeserialize(jsonNode.traverse(parser.getCodec()))
.getPayload());
}
if (errorNode.has(Constants.ERROR_CODE)) {
error.setCode(errorNode.get(Constants.ERROR_CODE).textValue());
}
if (errorNode.has(Constants.ERROR_MESSAGE)) {
final JsonNode message = errorNode.get(Constants.ERROR_MESSAGE);
if (message.isValueNode()) {
error.setMessage(message.textValue());
} else if (message.isObject()) {
error.setMessage(message.get(Constants.VALUE).asText());
}
}
if (errorNode.has(Constants.ERROR_TARGET)) {
error.setTarget(errorNode.get(Constants.ERROR_TARGET).textValue());
}
if (errorNode.hasNonNull(Constants.ERROR_DETAILS)) {
List<ODataErrorDetail> details = new ArrayList<>();
JsonODataErrorDetailDeserializer detailDeserializer =
new JsonODataErrorDetailDeserializer(serverMode);
for (JsonNode jsonNode : errorNode.get(Constants.ERROR_DETAILS)) {
details.add(detailDeserializer.doDeserialize(
jsonNode.traverse(parser.getCodec())).getPayload());
}

error.setDetails(details);
}
if (errorNode.hasNonNull(Constants.ERROR_INNERERROR)) {
HashMap<String, String> innerErrorMap = new HashMap<>();
final JsonNode innerError = errorNode.get(Constants.ERROR_INNERERROR);
for (final Iterator<String> itor = innerError.fieldNames(); itor.hasNext();) {
final String keyTmp = itor.next();
final String val = innerError.get(keyTmp).toString();
innerErrorMap.put(keyTmp, val);
}
error.setInnerError(innerErrorMap);
}
}
error.setDetails(details);
}
if (errorNode.hasNonNull(Constants.ERROR_INNERERROR)) {
HashMap<String, String> innerErrorMap = new HashMap<>();
final JsonNode innerError = errorNode.get(Constants.ERROR_INNERERROR);
for (final Iterator<String> itor = innerError.fieldNames(); itor.hasNext();) {
final String keyTmp = itor.next();
final String val = innerError.get(keyTmp).toString();
innerErrorMap.put(keyTmp, val);
}
error.setInnerError(innerErrorMap);
}
} else if (tree.has(Constants.ERROR_CODE)) {
if (tree.has(Constants.ERROR_CODE)) {
error.setCode(tree.get(Constants.ERROR_CODE).textValue());
}
if (tree.has(Constants.ERROR_MESSAGE)) {
final JsonNode message = tree.get(Constants.ERROR_MESSAGE);
if (message.isValueNode()) {
error.setMessage(message.textValue());
} else if (message.isObject()) {
error.setMessage(message.get(Constants.VALUE).asText());
}
}
if (tree.has(Constants.ERROR_TARGET)) {
error.setTarget(tree.get(Constants.ERROR_TARGET).textValue());
}
if (tree.hasNonNull(Constants.ERROR_DETAILS)) {
List<ODataErrorDetail> details = new ArrayList<>();
JsonODataErrorDetailDeserializer detailDeserializer =
new JsonODataErrorDetailDeserializer(serverMode);
for (JsonNode jsonNode : tree.get(Constants.ERROR_DETAILS)) {
details.add(detailDeserializer.doDeserialize(
jsonNode.traverse(parser.getCodec())).getPayload());
}

return error;
}
error.setDetails(details);
}
if (tree.hasNonNull(Constants.ERROR_INNERERROR)) {
HashMap<String, String> innerErrorMap = new HashMap<>();
final JsonNode innerError = tree.get(Constants.ERROR_INNERERROR);
for (final Iterator<String> itor = innerError.fieldNames(); itor.hasNext();) {
final String keyTmp = itor.next();
final String val = innerError.get(keyTmp).toString();
innerErrorMap.put(keyTmp, val);
}
error.setInnerError(innerErrorMap);
}
}

return error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ protected void odataNavigationLinks(final EdmType edmType,
final Linked linked, final ClientLinked odataLinked, final String metadataETag, final URI base) {
for (Link link : linked.getNavigationLinks()) {
final String href = link.getHref();
if (href==null) {
continue; // @odata.nextLink is missing, ignore.
}
final String title = link.getTitle();
final Entity inlineEntity = link.getInlineEntity();
final EntityCollection inlineEntitySet = link.getInlineEntitySet();
Expand Down Expand Up @@ -851,8 +854,9 @@ protected ClientValue getODataValue(FullQualifiedName type,
value.asCollection().add(getODataValue(type, fake, contextURL, metadataETag));
}
} else if (valuable.isEnum()) {
Object enumValue = valuable.asEnum();
value = client.getObjectFactory().newEnumValue(type == null ? null : type.toString(),
valuable.asEnum().toString());
enumValue==null? null: enumValue.toString());
} else if (valuable.isComplex()) {
final ClientComplexValue lcValue =
client.getObjectFactory().newComplexValue(type == null ? null : type.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private void annotated(final ContentType contentType) throws EdmPrimitiveTypeExc
assertEquals("com.contoso.display.styleType", annotation.getValue().getTypeName());
assertTrue(annotation.hasComplexValue());
assertEquals(2,
annotation.getValue().asComplex().get("order").getPrimitiveValue().toCastValue(Integer.class), 0);
annotation.getValue().asComplex().get("order").getPrimitiveValue().toCastValue(Integer.class).intValue(), 0);

final ClientEntity written = client.getBinder().getODataEntity(
new ResWrap<Entity>((URI) null, null, client.getBinder().getEntity(entity)));
Expand Down
2 changes: 1 addition & 1 deletion lib/commons-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<parent>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-lib</artifactId>
<version>4.8.0-SNAPSHOT</version>
<version>4.8.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,6 @@ List<EdmFunction> getBoundFunctionsWithBindingType(FullQualifiedName bindingPara
* @return {@link EdmAnnotations}
*/
EdmAnnotations getAnnotationGroup(FullQualifiedName targetName, String qualifier);

EdmEntityType getEntityType(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ public interface EdmAnnotatable {
* @return list of all annotations
*/
List<EdmAnnotation> getAnnotations();

EdmAnnotation getAnnotation(String termName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
*/
public interface EdmAnnotation extends EdmAnnotatable {

String getTermAsString();

/**
* @return the term of this annotation
*/
Expand All @@ -36,4 +38,6 @@ public interface EdmAnnotation extends EdmAnnotatable {
String getQualifier();

EdmExpression getExpression();

String getExpressionAsString();
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ public interface EdmEntityType extends EdmStructuredType {
*/
@Override
EdmEntityType getBaseType();

String getPrimaryKey();

String getLabel();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ public interface EdmMember extends EdmNamed, EdmAnnotatable {
* @return value of this member as string
*/
String getValue();

String getLabel();
}
Loading