[OLINGO-935] better type determination for client serializer + clean-up

Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
Klaus Straubinger 2016-07-12 15:51:40 +02:00 committed by Christian Amend
parent 8d51c870fa
commit 77423380bb
8 changed files with 238 additions and 273 deletions

View File

@ -1,98 +0,0 @@
/*
* 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.serialization;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.olingo.commons.api.Constants;
abstract class AbstractAtomDealer {
protected static final String TYPE_TEXT = "text";
protected final String namespaceMetadata;
protected final String namespaceData;
protected final String namespaceAtom;
protected final QName etagQName;
protected final QName metadataEtagQName;
protected final QName inlineQName;
protected final QName actionQName;
protected final QName propertiesQName;
protected final QName typeQName;
protected final QName nullQName;
protected final QName elementQName;
protected final QName countQName;
protected final QName uriQName;
protected final QName nextQName;
protected final QName annotationQName;
protected final QName contextQName;
protected final QName entryRefQName;
protected final QName propertyValueQName;
protected final QName deletedEntryQName;
protected final QName reasonQName;
protected final QName linkQName;
protected final QName deletedLinkQName;
protected final QName errorCodeQName;
protected final QName errorMessageQName;
protected final QName errorTargetQName;
public AbstractAtomDealer() {
namespaceMetadata = Constants.NS_METADATA;
namespaceData = Constants.NS_DATASERVICES;
namespaceAtom = Constants.NS_ATOM;
etagQName = new QName(namespaceMetadata, Constants.ATOM_ATTR_ETAG);
metadataEtagQName = new QName(namespaceMetadata, Constants.ATOM_ATTR_METADATAETAG);
inlineQName = new QName(namespaceMetadata, Constants.ATOM_ELEM_INLINE);
actionQName = new QName(namespaceMetadata, Constants.ATOM_ELEM_ACTION);
propertiesQName = new QName(namespaceMetadata, Constants.PROPERTIES);
typeQName = new QName(namespaceMetadata, Constants.ATTR_TYPE);
nullQName = new QName(namespaceMetadata, Constants.ATTR_NULL);
elementQName = new QName(namespaceMetadata, Constants.ELEM_ELEMENT);
countQName = new QName(namespaceMetadata, Constants.ATOM_ELEM_COUNT);
uriQName = new QName(namespaceData, Constants.ELEM_URI);
nextQName = new QName(namespaceData, Constants.NEXT_LINK_REL);
annotationQName = new QName(namespaceMetadata, Constants.ANNOTATION);
contextQName = new QName(namespaceMetadata, Constants.CONTEXT);
entryRefQName = new QName(namespaceMetadata, Constants.ATOM_ELEM_ENTRY_REF);
propertyValueQName = new QName(namespaceMetadata, Constants.VALUE);
deletedEntryQName = new QName(Constants.NS_ATOM_TOMBSTONE, Constants.ATOM_ELEM_DELETED_ENTRY);
reasonQName = new QName(namespaceMetadata, Constants.ELEM_REASON);
linkQName = new QName(namespaceMetadata, Constants.ATOM_ELEM_LINK);
deletedLinkQName = new QName(namespaceMetadata, Constants.ELEM_DELETED_LINK);
errorCodeQName = new QName(namespaceMetadata, Constants.ERROR_CODE);
errorMessageQName = new QName(namespaceMetadata, Constants.ERROR_MESSAGE);
errorTargetQName = new QName(namespaceMetadata, Constants.ERROR_TARGET);
}
protected void namespaces(final XMLStreamWriter writer) throws XMLStreamException {
writer.writeNamespace("", Constants.NS_ATOM);
writer.writeNamespace(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
writer.writeNamespace(Constants.PREFIX_METADATA, Constants.NS_METADATA);
writer.writeNamespace(Constants.PREFIX_DATASERVICES, Constants.NS_DATASERVICES);
writer.writeNamespace(Constants.PREFIX_GML, Constants.NS_GML);
writer.writeNamespace(Constants.PREFIX_GEORSS, Constants.NS_GEORSS);
}
}

View File

@ -65,7 +65,29 @@ import org.apache.olingo.commons.core.edm.EdmTypeInfo;
import com.fasterxml.aalto.stax.InputFactoryImpl;
public class AtomDeserializer extends AbstractAtomDealer implements ODataDeserializer {
public class AtomDeserializer implements ODataDeserializer {
protected static final QName etagQName = new QName(Constants.NS_METADATA, Constants.ATOM_ATTR_ETAG);
protected static final QName metadataEtagQName = new QName(Constants.NS_METADATA, Constants.ATOM_ATTR_METADATAETAG);
protected static final QName inlineQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_INLINE);
protected static final QName actionQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_ACTION);
protected static final QName propertiesQName = new QName(Constants.NS_METADATA, Constants.PROPERTIES);
protected static final QName typeQName = new QName(Constants.NS_METADATA, Constants.ATTR_TYPE);
protected static final QName nullQName = new QName(Constants.NS_METADATA, Constants.ATTR_NULL);
protected static final QName elementQName = new QName(Constants.NS_METADATA, Constants.ELEM_ELEMENT);
protected static final QName countQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_COUNT);
protected static final QName annotationQName = new QName(Constants.NS_METADATA, Constants.ANNOTATION);
protected static final QName contextQName = new QName(Constants.NS_METADATA, Constants.CONTEXT);
protected static final QName entryRefQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_ENTRY_REF);
protected static final QName propertyValueQName = new QName(Constants.NS_METADATA, Constants.VALUE);
protected static final QName reasonQName = new QName(Constants.NS_METADATA, Constants.ELEM_REASON);
protected static final QName linkQName = new QName(Constants.NS_METADATA, Constants.ATOM_ELEM_LINK);
protected static final QName deletedLinkQName = new QName(Constants.NS_METADATA, Constants.ELEM_DELETED_LINK);
protected static final QName errorCodeQName = new QName(Constants.NS_METADATA, Constants.ERROR_CODE);
protected static final QName errorMessageQName = new QName(Constants.NS_METADATA, Constants.ERROR_MESSAGE);
protected static final QName errorTargetQName = new QName(Constants.NS_METADATA, Constants.ERROR_TARGET);
protected static final QName deletedEntryQName =
new QName(Constants.NS_ATOM_TOMBSTONE, Constants.ATOM_ELEM_DELETED_ENTRY);
protected static final XMLInputFactory FACTORY = new InputFactoryImpl();

View File

@ -31,7 +31,6 @@ import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.client.api.serialization.ODataSerializer;
import org.apache.olingo.client.api.serialization.ODataSerializerException;
@ -56,12 +55,13 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import com.fasterxml.aalto.stax.OutputFactoryImpl;
public class AtomSerializer extends AbstractAtomDealer implements ODataSerializer {
public class AtomSerializer implements ODataSerializer {
private static final String TYPE_TEXT = "text";
private static final XMLOutputFactory FACTORY = new OutputFactoryImpl();
private final AtomGeoValueSerializer geoSerializer;
private final boolean serverMode;
public AtomSerializer() {
@ -73,11 +73,20 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
this.serverMode = serverMode;
}
protected void namespaces(XMLStreamWriter writer) throws XMLStreamException {
writer.writeNamespace("", Constants.NS_ATOM);
writer.writeNamespace(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
writer.writeNamespace(Constants.PREFIX_METADATA, Constants.NS_METADATA);
writer.writeNamespace(Constants.PREFIX_DATASERVICES, Constants.NS_DATASERVICES);
writer.writeNamespace(Constants.PREFIX_GML, Constants.NS_GML);
writer.writeNamespace(Constants.PREFIX_GEORSS, Constants.NS_GEORSS);
}
private void collection(final XMLStreamWriter writer,
final ValueType valueType, final EdmPrimitiveTypeKind kind, final List<?> value)
throws XMLStreamException, EdmPrimitiveTypeException {
for (Object item : value) {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ELEM_ELEMENT, namespaceMetadata);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ELEM_ELEMENT, Constants.NS_METADATA);
value(writer, valueType, kind, item);
writer.writeEndElement();
}
@ -86,16 +95,24 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
private void value(final XMLStreamWriter writer,
final ValueType valueType, final EdmPrimitiveTypeKind kind, final Object value)
throws XMLStreamException, EdmPrimitiveTypeException {
if (value == null || (valueType == ValueType.COMPLEX && ((ComplexValue)value).getValue().isEmpty())) {
writer.writeAttribute(Constants.PREFIX_METADATA, namespaceMetadata,
if (value == null || (valueType == ValueType.COMPLEX && ((ComplexValue) value).getValue().isEmpty())) {
writer.writeAttribute(Constants.PREFIX_METADATA, Constants.NS_METADATA,
Constants.ATTR_NULL, Boolean.TRUE.toString());
return;
}
switch (valueType) {
case PRIMITIVE:
writer.writeCharacters(kind == null ? value.toString() :
EdmPrimitiveTypeFactory.getInstance(kind) // TODO: add facets
.valueToString(value, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null));
final EdmPrimitiveTypeKind valueKind = kind == null ? EdmTypeInfo.determineTypeKind(value) : kind;
if (valueKind == null) {
if (serverMode) {
throw new EdmPrimitiveTypeException("The primitive type could not be determined.");
} else {
writer.writeCharacters(value.toString()); // This might not be valid OData.
}
} else {
writer.writeCharacters(EdmPrimitiveTypeFactory.getInstance(valueKind) // TODO: add facets
.valueToString(value, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null));
}
break;
case ENUM:
writer.writeCharacters(value.toString());
@ -124,22 +141,23 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
throws XMLStreamException, EdmPrimitiveTypeException {
if (standalone) {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.VALUE, namespaceData);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.VALUE, Constants.NS_DATASERVICES);
namespaces(writer);
} else {
writer.writeStartElement(Constants.PREFIX_DATASERVICES, property.getName(), namespaceData);
writer.writeStartElement(Constants.PREFIX_DATASERVICES, property.getName(), Constants.NS_DATASERVICES);
}
EdmTypeInfo typeInfo = null;
if (StringUtils.isNotBlank(property.getType())) {
if (property.getType() != null) {
typeInfo = new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build();
if (!EdmPrimitiveTypeKind.String.getFullQualifiedName().toString().equals(typeInfo.internal())) {
writer.writeAttribute(Constants.PREFIX_METADATA, namespaceMetadata,
writer.writeAttribute(Constants.PREFIX_METADATA, Constants.NS_METADATA,
Constants.ATTR_TYPE, typeInfo.external());
}
}
value(writer, property.getValueType(), typeInfo == null ? null : typeInfo.getPrimitiveTypeKind(),
value(writer, property.getValueType(),
typeInfo == null ? null : typeInfo.getPrimitiveTypeKind(),
property.getValue());
if (!property.isNull() && property.isComplex() && !property.isCollection()) {
links(writer, property.asComplex().getAssociationLinks());
@ -196,14 +214,14 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writeLink(writer, link, new ExtraContent() {
@Override
public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, Constants.NS_METADATA);
if (link.getInlineEntity() != null) {
writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_ENTRY);
writer.writeStartElement(Constants.NS_ATOM, Constants.ATOM_ELEM_ENTRY);
entity(writer, link.getInlineEntity());
writer.writeEndElement();
}
if (link.getInlineEntitySet() != null) {
writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
writer.writeStartElement(Constants.NS_ATOM, Constants.ATOM_ELEM_FEED);
entitySet(writer, link.getInlineEntitySet());
writer.writeEndElement();
}
@ -222,8 +240,8 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writeLink(writer, link, new ExtraContent() {
@Override
public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, Constants.NS_METADATA);
writer.writeStartElement(Constants.NS_ATOM, Constants.ATOM_ELEM_FEED);
for (String binding:link.getBindingLinks()) {
Entity entity = new Entity();
entity.setId(URI.create(binding));
@ -242,10 +260,10 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
uris = new ArrayList<String>();
entitySetLinks.put(link.getTitle(), uris);
}
if (StringUtils.isNotBlank(link.getHref())) {
if (link.getHref() != null) {
uris.add(link.getHref());
}
} else {
} else {
writeLink(writer, link, new ExtraContent() {
@Override
public void write(XMLStreamWriter writer, Link link)
@ -266,8 +284,8 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writeLink(writer, link, new ExtraContent() {
@Override
public void write(XMLStreamWriter writer, Link link) throws XMLStreamException, EdmPrimitiveTypeException {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, namespaceMetadata);
writer.writeStartElement(namespaceAtom, Constants.ATOM_ELEM_FEED);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ATOM_ELEM_INLINE, Constants.NS_METADATA);
writer.writeStartElement(Constants.NS_ATOM, Constants.ATOM_ELEM_FEED);
for (String binding:entitySetLink) {
Entity entity = new Entity();
entity.setId(URI.create(binding));
@ -280,7 +298,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
}
}
private void links(final XMLStreamWriter writer, final List<Link> links)
throws XMLStreamException, EdmPrimitiveTypeException {
for (Link link : links) {
@ -302,21 +320,21 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
throws XMLStreamException, EdmPrimitiveTypeException {
writer.writeStartElement(Constants.ATOM_ELEM_LINK);
if (StringUtils.isNotBlank(link.getRel())) {
if (link.getRel() != null) {
writer.writeAttribute(Constants.ATTR_REL, link.getRel());
}
if (StringUtils.isNotBlank(link.getTitle())) {
if (link.getTitle() != null) {
writer.writeAttribute(Constants.ATTR_TITLE, link.getTitle());
}
if (StringUtils.isNotBlank(link.getHref())) {
if (link.getHref() != null) {
writer.writeAttribute(Constants.ATTR_HREF, link.getHref());
}
if (StringUtils.isNotBlank(link.getType())) {
if (link.getType() != null) {
writer.writeAttribute(Constants.ATTR_TYPE, link.getType());
}
content.write(writer, link);
for (Annotation annotation : link.getAnnotations()) {
annotation(writer, annotation, null);
}
@ -324,7 +342,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
private void common(final XMLStreamWriter writer, final AbstractODataObject object) throws XMLStreamException {
if (StringUtils.isNotBlank(object.getTitle())) {
if (object.getTitle() != null) {
writer.writeStartElement(Constants.ATOM_ELEM_TITLE);
writer.writeAttribute(Constants.ATTR_TYPE, TYPE_TEXT);
writer.writeCharacters(object.getTitle());
@ -342,7 +360,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
private void annotation(final XMLStreamWriter writer, final Annotation annotation, final String target)
throws XMLStreamException, EdmPrimitiveTypeException {
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ANNOTATION, namespaceMetadata);
writer.writeStartElement(Constants.PREFIX_METADATA, Constants.ANNOTATION, Constants.NS_METADATA);
writer.writeAttribute(Constants.ATOM_ATTR_TERM, annotation.getTerm());
@ -351,15 +369,16 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
EdmTypeInfo typeInfo = null;
if (StringUtils.isNotBlank(annotation.getType())) {
if (annotation.getType() != null) {
typeInfo = new EdmTypeInfo.Builder().setTypeExpression(annotation.getType()).build();
if (!EdmPrimitiveTypeKind.String.getFullQualifiedName().toString().equals(typeInfo.internal())) {
writer.writeAttribute(Constants.PREFIX_METADATA, namespaceMetadata,
writer.writeAttribute(Constants.PREFIX_METADATA, Constants.NS_METADATA,
Constants.ATTR_TYPE, typeInfo.external());
}
}
value(writer, annotation.getValueType(), typeInfo == null ? null : typeInfo.getPrimitiveTypeKind(),
value(writer, annotation.getValueType(),
typeInfo == null ? EdmTypeInfo.determineTypeKind(annotation.getValue()) : typeInfo.getPrimitiveTypeKind(),
annotation.getValue());
writer.writeEndElement();
@ -371,8 +390,8 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeAttribute(XMLConstants.XML_NS_URI, Constants.ATTR_XML_BASE, entity.getBaseURI().toASCIIString());
}
if (serverMode && StringUtils.isNotBlank(entity.getETag())) {
writer.writeAttribute(namespaceMetadata, Constants.ATOM_ATTR_ETAG, entity.getETag());
if (serverMode && entity.getETag() != null) {
writer.writeAttribute(Constants.NS_METADATA, Constants.ATOM_ATTR_ETAG, entity.getETag());
}
if (entity.getId() != null) {
@ -383,7 +402,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeStartElement(Constants.ATOM_ELEM_CATEGORY);
writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
if (StringUtils.isNotBlank(entity.getType())) {
if (entity.getType() != null) {
writer.writeAttribute(Constants.ATOM_ATTR_TERM,
new EdmTypeInfo.Builder().setTypeExpression(entity.getType()).build().external());
}
@ -412,7 +431,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
if (serverMode) {
for (Operation operation : entity.getOperations()) {
writer.writeStartElement(namespaceMetadata, Constants.ATOM_ELEM_ACTION);
writer.writeStartElement(Constants.NS_METADATA, Constants.ATOM_ELEM_ACTION);
writer.writeAttribute(Constants.ATTR_METADATA, operation.getMetadataAnchor());
writer.writeAttribute(Constants.ATTR_TITLE, operation.getTitle());
writer.writeAttribute(Constants.ATTR_TARGET, operation.getTarget().toASCIIString());
@ -422,7 +441,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeStartElement(Constants.ATOM_ELEM_CONTENT);
if (entity.isMediaEntity()) {
if (StringUtils.isNotBlank(entity.getMediaContentType())) {
if (entity.getMediaContentType() != null) {
writer.writeAttribute(Constants.ATTR_TYPE, entity.getMediaContentType());
}
if (entity.getMediaContentSource() != null) {
@ -430,11 +449,11 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
writer.writeEndElement();
writer.writeStartElement(namespaceMetadata, Constants.PROPERTIES);
writer.writeStartElement(Constants.NS_METADATA, Constants.PROPERTIES);
properties(writer, entity.getProperties());
} else {
writer.writeAttribute(Constants.ATTR_TYPE, ContentType.APPLICATION_XML.toContentTypeString());
writer.writeStartElement(namespaceMetadata, Constants.PROPERTIES);
writer.writeStartElement(Constants.NS_METADATA, Constants.PROPERTIES);
properties(writer, entity.getProperties());
writer.writeEndElement();
}
@ -446,21 +465,21 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
private void inlineEntityRef(final XMLStreamWriter writer, final Entity entity) throws XMLStreamException {
writer.writeStartElement(namespaceMetadata, Constants.ATOM_ELEM_ENTRY_REF);
writer.writeStartElement(Constants.NS_METADATA, Constants.ATOM_ELEM_ENTRY_REF);
writer.writeAttribute(Constants.ATOM_ATTR_ID, entity.getId().toASCIIString());
writer.writeEndElement();
}
private void entityRef(final XMLStreamWriter writer, final Entity entity) throws XMLStreamException {
writer.writeStartElement(Constants.ATOM_ELEM_ENTRY_REF);
writer.writeDefaultNamespace(namespaceMetadata);
writer.writeDefaultNamespace(Constants.NS_METADATA);
writer.writeAttribute(Constants.ATOM_ATTR_ID, entity.getId().toASCIIString());
writer.writeEndElement();
}
private void entityRef(final XMLStreamWriter writer, final ResWrap<Entity> container) throws XMLStreamException {
writer.writeStartElement(Constants.ATOM_ELEM_ENTRY_REF);
writer.writeDefaultNamespace(namespaceMetadata);
writer.writeDefaultNamespace(Constants.NS_METADATA);
addContextInfo(writer, container);
writer.writeAttribute(Constants.ATOM_ATTR_ID, container.getPayload().getId().toASCIIString());
}
@ -471,7 +490,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
if (entity.getType() == null && entity.getProperties().isEmpty()) {
writer.writeStartDocument();
writer.setDefaultNamespace(namespaceMetadata);
writer.setDefaultNamespace(Constants.NS_METADATA);
entityRef(writer, entity);
} else {
startDocument(writer, Constants.ATOM_ELEM_ENTRY);
@ -489,7 +508,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
if (entity.getType() == null && entity.getProperties().isEmpty()) {
writer.writeStartDocument();
writer.setDefaultNamespace(namespaceMetadata);
writer.setDefaultNamespace(Constants.NS_METADATA);
entityRef(writer, container);
} else {
@ -512,7 +531,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
}
if (entitySet.getCount() != null) {
writer.writeStartElement(namespaceMetadata, Constants.ATOM_ELEM_COUNT);
writer.writeStartElement(Constants.NS_METADATA, Constants.ATOM_ELEM_COUNT);
writer.writeCharacters(Integer.toString(entitySet.getCount()));
writer.writeEndElement();
}
@ -587,7 +606,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
writer.writeStartDocument();
writer.writeStartElement(Constants.ELEM_LINKS);
writer.writeDefaultNamespace(namespaceData);
writer.writeDefaultNamespace(Constants.NS_DATASERVICES);
writer.writeStartElement(Constants.ELEM_URI);
writer.writeCharacters(link.getHref());
@ -670,12 +689,12 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
((Entity) container.getPayload()).setBaseURI(base);
}
writer.writeAttribute(namespaceMetadata, Constants.CONTEXT,
writer.writeAttribute(Constants.NS_METADATA, Constants.CONTEXT,
container.getContextURL().toASCIIString());
}
if (StringUtils.isNotBlank(container.getMetadataETag())) {
writer.writeAttribute(namespaceMetadata, Constants.ATOM_ATTR_METADATAETAG,
if (container.getMetadataETag() != null) {
writer.writeAttribute(Constants.NS_METADATA, Constants.ATOM_ATTR_METADATAETAG,
container.getMetadataETag());
}
}

View File

@ -20,7 +20,6 @@ package org.apache.olingo.client.core.serialization;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Annotation;
@ -60,21 +59,21 @@ public class JsonEntitySerializer extends JsonSerializer {
if (container.getContextURL() != null) {
jgen.writeStringField(Constants.JSON_CONTEXT, container.getContextURL().toASCIIString());
}
if (StringUtils.isNotBlank(container.getMetadataETag())) {
if (container.getMetadataETag() != null) {
jgen.writeStringField(Constants.JSON_METADATA_ETAG, container.getMetadataETag());
}
if (StringUtils.isNotBlank(entity.getETag())) {
if (entity.getETag() != null) {
jgen.writeStringField(Constants.JSON_ETAG, entity.getETag());
}
}
if (StringUtils.isNotBlank(entity.getType()) && !isODataMetadataNone(contentType)) {
if (entity.getType() != null && !isODataMetadataNone) {
jgen.writeStringField(Constants.JSON_TYPE,
new EdmTypeInfo.Builder().setTypeExpression(entity.getType()).build().external());
}
if (entity.getId() != null && !isODataMetadataNone(contentType)) {
if (entity.getId() != null && !isODataMetadataNone) {
jgen.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString());
}
@ -86,9 +85,8 @@ public class JsonEntitySerializer extends JsonSerializer {
valuable(jgen, property, property.getName());
}
if (serverMode && entity.getEditLink() != null && StringUtils.isNotBlank(entity.getEditLink().getHref())) {
jgen.writeStringField(Constants.JSON_EDIT_LINK,
entity.getEditLink().getHref());
if (serverMode && entity.getEditLink() != null && entity.getEditLink().getHref() != null) {
jgen.writeStringField(Constants.JSON_EDIT_LINK, entity.getEditLink().getHref());
if (entity.isMediaEntity()) {
jgen.writeStringField(Constants.JSON_MEDIA_READ_LINK,
@ -96,7 +94,7 @@ public class JsonEntitySerializer extends JsonSerializer {
}
}
if (!isODataMetadataNone(contentType)) {
if (!isODataMetadataNone) {
links(entity, jgen);
}
@ -119,7 +117,9 @@ public class JsonEntitySerializer extends JsonSerializer {
if (serverMode) {
for (Operation operation : entity.getOperations()) {
jgen.writeObjectFieldStart("#" + StringUtils.substringAfterLast(operation.getMetadataAnchor(), "#"));
final String anchor = operation.getMetadataAnchor();
final int index = anchor.lastIndexOf('#');
jgen.writeObjectFieldStart('#' + anchor.substring(index < 0 ? 0 : (index + 1)));
jgen.writeStringField(Constants.ATTR_TITLE, operation.getTitle());
jgen.writeStringField(Constants.ATTR_TARGET, operation.getTarget().toASCIIString());
jgen.writeEndObject();
@ -128,4 +128,4 @@ public class JsonEntitySerializer extends JsonSerializer {
jgen.writeEndObject();
}
}
}

View File

@ -20,7 +20,6 @@ package org.apache.olingo.client.core.serialization;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Annotation;
@ -54,18 +53,20 @@ public class JsonEntitySetSerializer extends JsonSerializer {
jgen.writeStringField(Constants.JSON_CONTEXT, container.getContextURL().toASCIIString());
}
if (StringUtils.isNotBlank(container.getMetadataETag())) {
jgen.writeStringField(
Constants.JSON_METADATA_ETAG,
container.getMetadataETag());
if (container.getMetadataETag() != null) {
jgen.writeStringField(Constants.JSON_METADATA_ETAG, container.getMetadataETag());
}
}
if (entitySet.getId() != null) {
jgen.writeStringField(Constants.JSON_ID, entitySet.getId().toASCIIString());
}
jgen.writeNumberField(Constants.JSON_COUNT,
entitySet.getCount() == null ? entitySet.getEntities().size() : entitySet.getCount());
final Integer count = entitySet.getCount() == null ? entitySet.getEntities().size() : entitySet.getCount();
if (isIEEE754Compatible) {
jgen.writeStringField(Constants.JSON_COUNT, Integer.toString(count));
} else {
jgen.writeNumberField(Constants.JSON_COUNT, count);
}
if (serverMode) {
if (entitySet.getNext() != null) {
jgen.writeStringField(Constants.JSON_NEXT_LINK,

View File

@ -22,12 +22,11 @@ import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.client.api.serialization.ODataSerializer;
import org.apache.olingo.client.api.serialization.ODataSerializerException;
@ -54,23 +53,24 @@ import com.fasterxml.jackson.core.JsonGenerator;
public class JsonSerializer implements ODataSerializer {
private static final EdmPrimitiveTypeKind[] NUMBER_TYPES = {
private static final List<EdmPrimitiveTypeKind> NUMBER_TYPES = Arrays.asList(
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
EdmPrimitiveTypeKind.Decimal
};
EdmPrimitiveTypeKind.Decimal);
private final JsonGeoValueSerializer geoSerializer = new JsonGeoValueSerializer();
protected boolean serverMode;
protected final boolean isIEEE754Compatible;
protected ContentType contentType;
protected final boolean isIEEE754Compatible;
protected final boolean isODataMetadataNone;
public JsonSerializer(final boolean serverMode, final ContentType contentType) {
this.serverMode = serverMode;
this.contentType = contentType;
this.isIEEE754Compatible = isIEEE754Compatible();
this.isODataMetadataNone = isODataMetadataNone();
}
@Override
@ -162,11 +162,11 @@ public class JsonSerializer implements ODataSerializer {
uris = new ArrayList<String>();
entitySetLinks.put(link.getTitle(), uris);
}
if (StringUtils.isNotBlank(link.getHref())) {
if (link.getHref() != null && !link.getHref().isEmpty()) {
uris.add(link.getHref());
}
} else {
if (StringUtils.isNotBlank(link.getHref())) {
if (link.getHref() != null && !link.getHref().isEmpty()) {
jgen.writeStringField(link.getTitle() + Constants.JSON_BIND_LINK_SUFFIX, link.getHref());
}
}
@ -202,19 +202,15 @@ public class JsonSerializer implements ODataSerializer {
throws IOException, EdmPrimitiveTypeException {
if (linked instanceof Entity) {
for (Link link : ((Entity) linked).getMediaEditLinks()) {
if (StringUtils.isNotBlank(link.getHref())) {
jgen.writeStringField(
link.getTitle() + StringUtils.prependIfMissing(Constants.JSON_MEDIA_EDIT_LINK, "@"),
link.getHref());
if (link.getHref() != null && !link.getHref().isEmpty()) {
jgen.writeStringField(link.getTitle() + Constants.JSON_MEDIA_EDIT_LINK, link.getHref());
}
}
}
for (Link link : linked.getAssociationLinks()) {
if (StringUtils.isNotBlank(link.getHref())) {
jgen.writeStringField(
link.getTitle() + Constants.JSON_ASSOCIATION_LINK,
link.getHref());
if (link.getHref() != null && !link.getHref().isEmpty()) {
jgen.writeStringField(link.getTitle() + Constants.JSON_ASSOCIATION_LINK, link.getHref());
}
}
@ -223,10 +219,8 @@ public class JsonSerializer implements ODataSerializer {
valuable(jgen, annotation, link.getTitle() + "@" + annotation.getTerm());
}
if (StringUtils.isNotBlank(link.getHref())) {
jgen.writeStringField(
link.getTitle() + Constants.JSON_NAVIGATION_LINK,
link.getHref());
if (link.getHref() != null && !link.getHref().isEmpty()) {
jgen.writeStringField(link.getTitle() + Constants.JSON_NAVIGATION_LINK, link.getHref());
}
if (link.getInlineEntity() != null) {
@ -247,12 +241,13 @@ public class JsonSerializer implements ODataSerializer {
final ValueType valueType, final List<?> value)
throws IOException, EdmPrimitiveTypeException {
final EdmTypeInfo itemTypeInfo = typeInfo == null ?
null :
new EdmTypeInfo.Builder().setTypeExpression(typeInfo.getFullQualifiedName().toString()).build();
jgen.writeStartArray();
for (Object item : value) {
final EdmTypeInfo itemTypeInfo = typeInfo == null
? null
: new EdmTypeInfo.Builder().setTypeExpression(typeInfo.getFullQualifiedName().toString()).build();
switch (valueType) {
case COLLECTION_PRIMITIVE:
primitiveValue(jgen, itemTypeInfo, item);
@ -283,37 +278,40 @@ public class JsonSerializer implements ODataSerializer {
protected void primitiveValue(final JsonGenerator jgen, final EdmTypeInfo typeInfo, final Object value)
throws IOException, EdmPrimitiveTypeException {
final EdmPrimitiveTypeKind kind = typeInfo == null ? null : typeInfo.getPrimitiveTypeKind();
final boolean isNumber = kind == null ? value instanceof Number : ArrayUtils.contains(NUMBER_TYPES, kind);
final boolean isBoolean = kind == null ? value instanceof Boolean : kind == EdmPrimitiveTypeKind.Boolean;
final EdmPrimitiveTypeKind kind = typeInfo == null ?
EdmTypeInfo.determineTypeKind(value) :
typeInfo.getPrimitiveTypeKind();
if (value == null) {
jgen.writeNull();
} else if (isBoolean) {
} else if (kind == EdmPrimitiveTypeKind.Boolean) {
jgen.writeBoolean((Boolean) value);
} else if (kind == null) {
if (serverMode) {
throw new EdmPrimitiveTypeException("The primitive type could not be determined.");
} else {
jgen.writeString(value.toString()); // This might not be valid OData.
}
} else {
String serialized = kind == null
? value.toString()
// TODO: add facets
: EdmPrimitiveTypeFactory.getInstance(kind).
valueToString(value, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null);
if(isIEEE754Compatible && (kind == EdmPrimitiveTypeKind.Int64 || kind == EdmPrimitiveTypeKind.Decimal)) {
jgen.writeString(serialized);
} else if(isNumber) {
jgen.writeNumber(serialized);
} else {
jgen.writeString(serialized);
}
// TODO: add facets
final String serialized = EdmPrimitiveTypeFactory.getInstance(kind)
.valueToString(value, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null);
if (isIEEE754Compatible && (kind == EdmPrimitiveTypeKind.Int64 || kind == EdmPrimitiveTypeKind.Decimal)
|| !NUMBER_TYPES.contains(kind)) {
jgen.writeString(serialized);
} else {
jgen.writeNumber(serialized);
}
}
}
private void complexValue(final JsonGenerator jgen, final EdmTypeInfo typeInfo,
final List<Property> value, final Linked linked)
throws IOException, EdmPrimitiveTypeException {
throws IOException, EdmPrimitiveTypeException {
jgen.writeStartObject();
if (typeInfo != null && !isODataMetadataNone(contentType)) {
if (typeInfo != null && !isODataMetadataNone) {
jgen.writeStringField(Constants.JSON_TYPE, typeInfo.external());
}
@ -356,14 +354,14 @@ public class JsonSerializer implements ODataSerializer {
String type = valuable.getType();
if ((!valuable.isCollection() &&
StringUtils.isBlank(type) &&
(type == null || type.isEmpty()) &&
valuable.isPrimitive()) || valuable.isNull()) {
type = EdmPrimitiveTypeKind.String.getFullQualifiedName().toString();
}
if (StringUtils.isNotBlank(type) && !isODataMetadataNone(contentType)) {
jgen.writeFieldName(
name + StringUtils.prependIfMissing(Constants.JSON_TYPE, "@"));
jgen.writeString(new EdmTypeInfo.Builder().setTypeExpression(type).build().external());
if (type != null && !type.isEmpty() && !isODataMetadataNone) {
jgen.writeStringField(
name + Constants.JSON_TYPE,
new EdmTypeInfo.Builder().setTypeExpression(type).build().external());
}
}
@ -374,14 +372,15 @@ public class JsonSerializer implements ODataSerializer {
jgen.writeFieldName(name);
value(jgen, valuable.getType(), valuable);
}
private boolean isIEEE754Compatible() {
final String parameter = contentType.getParameters().get(ContentType.PARAMETER_IEEE754_COMPATIBLE);
return parameter == null ? false : "true".equals(parameter.toLowerCase());
}
protected boolean isODataMetadataNone(final ContentType contentType) {
return contentType.isCompatible(ContentType.APPLICATION_JSON)
&& ContentType.VALUE_ODATA_METADATA_NONE.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
private boolean isODataMetadataNone() {
return contentType.isCompatible(ContentType.APPLICATION_JSON)
&& ContentType.VALUE_ODATA_METADATA_NONE.equals(
contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
}
}
}

View File

@ -33,6 +33,7 @@ import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientLink;
import org.apache.olingo.client.api.domain.ClientProperty;
import org.apache.olingo.client.api.serialization.ODataSerializer;
import org.apache.olingo.client.api.serialization.ODataSerializerException;
import org.apache.olingo.client.api.serialization.ODataWriter;
import org.apache.olingo.commons.api.Constants;
@ -57,8 +58,9 @@ public class ODataWriterImpl implements ODataWriter {
writer = null;
}
try {
final ODataSerializer serializer = client.getSerializer(contentType);
for (ClientEntity entity : entities) {
client.getSerializer(contentType).write(writer, client.getBinder().getEntity(entity));
serializer.write(writer, client.getBinder().getEntity(entity));
}
return new ByteArrayInputStream(output.toByteArray());

View File

@ -18,6 +18,12 @@
*/
package org.apache.olingo.commons.core.edm;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -34,7 +40,6 @@ public class EdmTypeInfo {
public static class Builder {
private String typeExpression;
private String defaultNamespace;
private Edm edm;
public Builder setTypeExpression(final String typeExpression) {
@ -42,21 +47,13 @@ public class EdmTypeInfo {
return this;
}
public Builder setDefaultNamespace(final String defaultNamespace) {
this.defaultNamespace = defaultNamespace;
return this;
}
public Builder setEdm(final Edm edm) {
this.edm = edm;
return this;
}
public EdmTypeInfo build() {
return new EdmTypeInfo(edm,
typeExpression.indexOf('.') == -1 && defaultNamespace != null && !defaultNamespace.isEmpty() ?
defaultNamespace + "." + typeExpression :
typeExpression);
return new EdmTypeInfo(edm, typeExpression);
}
}
@ -84,10 +81,12 @@ public class EdmTypeInfo {
baseType = typeExpression.substring(collStartIdx + 11, collEndIdx);
}
baseType = baseType.replaceAll("^#", "");
if (baseType.startsWith("#")) {
baseType = baseType.substring(1);
}
final String typeName;
final String namespace;
String typeName;
String namespace;
final int lastDotIdx = baseType.lastIndexOf('.');
if (lastDotIdx == -1) {
@ -105,7 +104,7 @@ public class EdmTypeInfo {
fullQualifiedName = new FullQualifiedName(namespace, typeName);
try {
primitiveType = EdmPrimitiveTypeKind.valueOf(fullQualifiedName.getName());
primitiveType = EdmPrimitiveTypeKind.valueOf(typeName);
} catch (final IllegalArgumentException e) {
primitiveType = null;
}
@ -124,41 +123,30 @@ public class EdmTypeInfo {
}
public String internal() {
final StringBuilder deserialize = new StringBuilder();
if (isCollection()) {
deserialize.append("Collection(");
}
deserialize.append(getFullQualifiedName().toString());
if (isCollection()) {
deserialize.append(")");
}
return deserialize.toString();
return serialize(false);
}
public String external() {
final StringBuilder serialize = new StringBuilder();
return serialize(true);
}
private String serialize(final boolean external) {
StringBuilder serialize = new StringBuilder();
if (external && (!isPrimitiveType() || isCollection())) {
serialize.append('#');
}
if (isCollection()) {
serialize.append('#');
serialize.append("Collection(");
}
if (isPrimitiveType()) {
serialize.append(getFullQualifiedName().getName());
} else {
serialize.append(getFullQualifiedName().toString());
}
serialize.append(external && isPrimitiveType() ?
getFullQualifiedName().getName() :
getFullQualifiedName().getFullQualifiedNameAsString());
if (isCollection()) {
serialize.append(")");
}
if (!isPrimitiveType() && !isCollection()) {
serialize.insert(0, '#');
serialize.append(')');
}
return serialize.toString();
@ -213,16 +201,48 @@ public class EdmTypeInfo {
}
public EdmType getType() {
return isPrimitiveType()
? EdmPrimitiveTypeFactory.getInstance(getPrimitiveTypeKind())
: isTypeDefinition()
? getTypeDefinition()
: isEnumType()
? getEnumType()
: isComplexType()
? getComplexType()
: isEntityType()
? getEntityType()
: null;
return isPrimitiveType() ? EdmPrimitiveTypeFactory.getInstance(getPrimitiveTypeKind()) :
isTypeDefinition() ? getTypeDefinition() :
isEnumType() ? getEnumType() :
isComplexType() ? getComplexType() :
isEntityType() ? getEntityType() :
null;
}
public static EdmPrimitiveTypeKind determineTypeKind(final Object value) {
if (value == null) {
return null;
}
final Class<? extends Object> cls = value.getClass();
if (value instanceof Boolean || boolean.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Boolean;
} else if (value instanceof String) {
return EdmPrimitiveTypeKind.String;
} else if (value instanceof UUID) {
return EdmPrimitiveTypeKind.Guid;
} else if (value instanceof Long || value instanceof BigInteger || long.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Int64;
} else if (value instanceof Integer || int.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Int32;
} else if (value instanceof Short || short.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Int16;
} else if (value instanceof Byte || byte.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.SByte;
} else if (value instanceof BigDecimal) {
return EdmPrimitiveTypeKind.Decimal;
} else if (value instanceof Double || double.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Double;
} else if (value instanceof Float || float.class.isAssignableFrom(cls)) {
return EdmPrimitiveTypeKind.Single;
} else if (value instanceof Calendar || value instanceof Date || value instanceof java.sql.Timestamp) {
return EdmPrimitiveTypeKind.DateTimeOffset;
} else if (value instanceof java.sql.Date) {
return EdmPrimitiveTypeKind.Date;
} else if (value instanceof java.sql.Time) {
return EdmPrimitiveTypeKind.TimeOfDay;
} else if (value instanceof byte[] || value instanceof Byte[]) {
return EdmPrimitiveTypeKind.Binary;
}
return null;
}
}