mirror of
https://github.com/apache/olingo-odata4.git
synced 2025-02-06 01:59:12 +00:00
OLINGO-878: Adding support to remove unvalid xml characters from Atom payload
This commit is contained in:
parent
3c205f907e
commit
d880d6c480
@ -28,6 +28,7 @@ public class ComplexSerializerOptions {
|
|||||||
private ContextURL contextURL;
|
private ContextURL contextURL;
|
||||||
private ExpandOption expand;
|
private ExpandOption expand;
|
||||||
private SelectOption select;
|
private SelectOption select;
|
||||||
|
private String xml10InvalidCharReplacement;
|
||||||
|
|
||||||
/** Gets the {@link ContextURL}. */
|
/** Gets the {@link ContextURL}. */
|
||||||
public ContextURL getContextURL() {
|
public ContextURL getContextURL() {
|
||||||
@ -44,6 +45,11 @@ public class ComplexSerializerOptions {
|
|||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||||
|
public String xml10InvalidCharReplacement() {
|
||||||
|
return xml10InvalidCharReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
private ComplexSerializerOptions() {}
|
private ComplexSerializerOptions() {}
|
||||||
|
|
||||||
/** Initializes the options builder. */
|
/** Initializes the options builder. */
|
||||||
@ -78,6 +84,12 @@ public class ComplexSerializerOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
|
||||||
|
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||||
|
options.xml10InvalidCharReplacement = replacement;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the OData serializer options. */
|
/** Builds the OData serializer options. */
|
||||||
public ComplexSerializerOptions build() {
|
public ComplexSerializerOptions build() {
|
||||||
return options;
|
return options;
|
||||||
|
@ -32,6 +32,7 @@ public class EntityCollectionSerializerOptions {
|
|||||||
private SelectOption select;
|
private SelectOption select;
|
||||||
private boolean writeOnlyReferences;
|
private boolean writeOnlyReferences;
|
||||||
private String id;
|
private String id;
|
||||||
|
private String xml10InvalidCharReplacement;
|
||||||
|
|
||||||
/** Gets the {@link ContextURL}. */
|
/** Gets the {@link ContextURL}. */
|
||||||
public ContextURL getContextURL() {
|
public ContextURL getContextURL() {
|
||||||
@ -63,6 +64,11 @@ public class EntityCollectionSerializerOptions {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||||
|
public String xml10InvalidCharReplacement() {
|
||||||
|
return xml10InvalidCharReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
/** Initializes the options builder. */
|
/** Initializes the options builder. */
|
||||||
public static Builder with() {
|
public static Builder with() {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
@ -113,6 +119,12 @@ public class EntityCollectionSerializerOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the replacement String for xml 1.0 unicode controlled characters that are not allowed */
|
||||||
|
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||||
|
options.xml10InvalidCharReplacement = replacement;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the OData serializer options. */
|
/** Builds the OData serializer options. */
|
||||||
public EntityCollectionSerializerOptions build() {
|
public EntityCollectionSerializerOptions build() {
|
||||||
return options;
|
return options;
|
||||||
|
@ -28,6 +28,7 @@ public class EntitySerializerOptions {
|
|||||||
private ExpandOption expand;
|
private ExpandOption expand;
|
||||||
private SelectOption select;
|
private SelectOption select;
|
||||||
private boolean writeOnlyReferences;
|
private boolean writeOnlyReferences;
|
||||||
|
private String xml10InvalidCharReplacement;
|
||||||
|
|
||||||
/** Gets the {@link ContextURL}. */
|
/** Gets the {@link ContextURL}. */
|
||||||
public ContextURL getContextURL() {
|
public ContextURL getContextURL() {
|
||||||
@ -49,6 +50,11 @@ public class EntitySerializerOptions {
|
|||||||
return writeOnlyReferences;
|
return writeOnlyReferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||||
|
public String xml10InvalidCharReplacement() {
|
||||||
|
return xml10InvalidCharReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
private EntitySerializerOptions() {}
|
private EntitySerializerOptions() {}
|
||||||
|
|
||||||
/** Initializes the options builder. */
|
/** Initializes the options builder. */
|
||||||
@ -89,6 +95,12 @@ public class EntitySerializerOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
|
||||||
|
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||||
|
options.xml10InvalidCharReplacement = replacement;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the OData serializer options. */
|
/** Builds the OData serializer options. */
|
||||||
public EntitySerializerOptions build() {
|
public EntitySerializerOptions build() {
|
||||||
return options;
|
return options;
|
||||||
|
@ -30,6 +30,7 @@ public final class PrimitiveSerializerOptions {
|
|||||||
private Integer precision;
|
private Integer precision;
|
||||||
private Integer scale;
|
private Integer scale;
|
||||||
private Boolean isUnicode;
|
private Boolean isUnicode;
|
||||||
|
private String xml10InvalidCharReplacement;
|
||||||
|
|
||||||
/** Gets the {@link ContextURL}. */
|
/** Gets the {@link ContextURL}. */
|
||||||
public ContextURL getContextURL() {
|
public ContextURL getContextURL() {
|
||||||
@ -61,6 +62,12 @@ public final class PrimitiveSerializerOptions {
|
|||||||
return isUnicode;
|
return isUnicode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||||
|
public String xml10InvalidCharReplacement() {
|
||||||
|
return xml10InvalidCharReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private PrimitiveSerializerOptions() {}
|
private PrimitiveSerializerOptions() {}
|
||||||
|
|
||||||
/** Initializes the options builder. */
|
/** Initializes the options builder. */
|
||||||
@ -123,6 +130,12 @@ public final class PrimitiveSerializerOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
|
||||||
|
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||||
|
options.xml10InvalidCharReplacement = replacement;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the OData serializer options. */
|
/** Builds the OData serializer options. */
|
||||||
public PrimitiveSerializerOptions build() {
|
public PrimitiveSerializerOptions build() {
|
||||||
return options;
|
return options;
|
||||||
|
@ -28,6 +28,7 @@ public class PrimitiveValueSerializerOptions {
|
|||||||
private Integer precision;
|
private Integer precision;
|
||||||
private Integer scale;
|
private Integer scale;
|
||||||
private Boolean isUnicode;
|
private Boolean isUnicode;
|
||||||
|
private String xml10InvalidCharReplacement;
|
||||||
|
|
||||||
/** Gets the nullable facet. */
|
/** Gets the nullable facet. */
|
||||||
public Boolean isNullable() {
|
public Boolean isNullable() {
|
||||||
@ -54,6 +55,11 @@ public class PrimitiveValueSerializerOptions {
|
|||||||
return isUnicode;
|
return isUnicode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||||
|
public String xml10InvalidCharReplacement() {
|
||||||
|
return xml10InvalidCharReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
private PrimitiveValueSerializerOptions() {}
|
private PrimitiveValueSerializerOptions() {}
|
||||||
|
|
||||||
/** Initializes the options builder. */
|
/** Initializes the options builder. */
|
||||||
@ -110,6 +116,12 @@ public class PrimitiveValueSerializerOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the replacement string for xml 1.0 unicode controlled characters that are not allowed */
|
||||||
|
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||||
|
options.xml10InvalidCharReplacement = replacement;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the OData serializer options. */
|
/** Builds the OData serializer options. */
|
||||||
public PrimitiveValueSerializerOptions build() {
|
public PrimitiveValueSerializerOptions build() {
|
||||||
return options;
|
return options;
|
||||||
|
@ -97,57 +97,93 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceIncludeAnnotation;
|
|||||||
public class MetadataParser {
|
public class MetadataParser {
|
||||||
private boolean parseAnnotations = false;
|
private boolean parseAnnotations = false;
|
||||||
private static final String XML_LINK_NS = "http://www.w3.org/1999/xlink";
|
private static final String XML_LINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
private ReferenceResolver defaultReferenceResolver = new DefaultReferenceResolver();
|
private ReferenceResolver referenceResolver = new DefaultReferenceResolver();
|
||||||
private boolean loadCoreVocabularies = false;
|
private boolean useLocalCoreVocabularies = true;
|
||||||
|
private boolean implicitlyLoadCoreVocabularies = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avoid reading the annotations in the $metadata
|
||||||
|
* @param parse
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public MetadataParser parseAnnotations(boolean parse) {
|
public MetadataParser parseAnnotations(boolean parse) {
|
||||||
this.parseAnnotations = parse;
|
this.parseAnnotations = parse;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Externalize the reference loading, such that they can be loaded from local caches
|
||||||
|
* @param resolver
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public MetadataParser referenceResolver(ReferenceResolver resolver) {
|
public MetadataParser referenceResolver(ReferenceResolver resolver) {
|
||||||
this.defaultReferenceResolver = resolver;
|
this.referenceResolver = resolver;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataParser loadCoreVocabularies(boolean load) {
|
/**
|
||||||
this.loadCoreVocabularies = load;
|
* Load the core libraries from local classpath
|
||||||
|
* @param load true for yes; false otherwise
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public MetadataParser useLocalCoreVocabularies(boolean load) {
|
||||||
|
this.useLocalCoreVocabularies = load;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the core vocabularies, irrespective of if they are defined in the $metadata
|
||||||
|
* @param load
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public MetadataParser implicitlyLoadCoreVocabularies(boolean load) {
|
||||||
|
this.implicitlyLoadCoreVocabularies = load;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
|
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
|
||||||
SchemaBasedEdmProvider provider = buildEdmProvider(csdl,
|
SchemaBasedEdmProvider provider = buildEdmProvider(csdl, this.referenceResolver,
|
||||||
this.defaultReferenceResolver, this.loadCoreVocabularies);
|
this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies);
|
||||||
return new ServiceMetadataImpl(provider, provider.getReferences(), null);
|
return new ServiceMetadataImpl(provider, provider.getReferences(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
public SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
||||||
return buildEdmProvider(csdl, this.defaultReferenceResolver, this.loadCoreVocabularies);
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||||
|
return buildEdmProvider(reader, this.referenceResolver,
|
||||||
|
this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl,
|
protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl,
|
||||||
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
|
ReferenceResolver resolver, boolean loadCore, boolean useLocal)
|
||||||
|
throws XMLStreamException {
|
||||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||||
return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
|
return buildEdmProvider(reader, resolver, loadCore, useLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl,
|
protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl,
|
||||||
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
|
ReferenceResolver resolver, boolean loadCore, boolean useLocal)
|
||||||
|
throws XMLStreamException {
|
||||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||||
return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
|
return buildEdmProvider(reader, resolver, loadCore, useLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader,
|
protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader,
|
||||||
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
|
ReferenceResolver resolver, boolean loadCore, boolean useLocal)
|
||||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver);
|
throws XMLStreamException {
|
||||||
|
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
||||||
|
|
||||||
|
final StringBuilder xmlBase = new StringBuilder();
|
||||||
|
|
||||||
new ElementReader<SchemaBasedEdmProvider>() {
|
new ElementReader<SchemaBasedEdmProvider>() {
|
||||||
@Override
|
@Override
|
||||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||||
String name) throws XMLStreamException {
|
String name) throws XMLStreamException {
|
||||||
String xmlBase = attrNS(element, XML_LINK_NS, "base");
|
if (attrNS(element, XML_LINK_NS, "base") != null) {
|
||||||
provider.setXMLBase(xmlBase);
|
xmlBase.append(attrNS(element, XML_LINK_NS, "base"));
|
||||||
|
}
|
||||||
String version = attr(element, "Version");
|
String version = attr(element, "Version");
|
||||||
if ("4.0".equals(version)) {
|
if ("4.0".equals(version)) {
|
||||||
readDataServicesAndReference(reader, element, provider);
|
readDataServicesAndReference(reader, element, provider);
|
||||||
@ -167,23 +203,100 @@ public class MetadataParser {
|
|||||||
event.asEndElement().getName().getLocalPart()));
|
event.asEndElement().getName().getLocalPart()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the core vocabularies
|
//load core vocabularies even though they are not defined in the references
|
||||||
if (loadCoreVocabularies) {
|
if (loadCore) {
|
||||||
loadVocabularySchema(provider, "Org.OData.Core.V1", "Org.OData.Core.V1.xml");
|
loadCoreVocabulary(provider, "Org.OData.Core.V1");
|
||||||
loadVocabularySchema(provider, "Org.OData.Capabilities.V1", "Org.OData.Capabilities.V1.xml");
|
loadCoreVocabulary(provider, "Org.OData.Capabilities.V1");
|
||||||
loadVocabularySchema(provider, "Org.OData.Measures.V1", "Org.OData.Measures.V1.xml");
|
loadCoreVocabulary(provider, "Org.OData.Measures.V1");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all the reference schemas
|
||||||
|
if (resolver != null) {
|
||||||
|
loadReferencesSchemas(provider, xmlBase.length() == 0 ? null
|
||||||
|
: fixXmlBase(xmlBase.toString()), resolver, loadCore, useLocal);
|
||||||
}
|
}
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadVocabularySchema(SchemaBasedEdmProvider provider, String namespace,
|
private void loadReferencesSchemas(SchemaBasedEdmProvider provider,
|
||||||
|
String xmlBase, ReferenceResolver resolver, boolean loadCore,
|
||||||
|
boolean useLocal) {
|
||||||
|
|
||||||
|
for (EdmxReference reference:provider.getReferences()) {
|
||||||
|
try {
|
||||||
|
SchemaBasedEdmProvider refProvider = null;
|
||||||
|
|
||||||
|
for (EdmxReferenceInclude include : reference.getIncludes()) {
|
||||||
|
|
||||||
|
// check if the schema is already loaded before.
|
||||||
|
if (provider.getSchema(include.getNamespace()) != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCoreVocabulary(include.getNamespace()) && useLocal) {
|
||||||
|
loadCoreVocabulary(provider, include.getNamespace());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refProvider == null) {
|
||||||
|
InputStream is = this.referenceResolver.resolveReference(reference.getUri(), xmlBase);
|
||||||
|
if (is == null) {
|
||||||
|
throw new EdmException("Failed to load Reference "+reference.getUri()+" loading failed");
|
||||||
|
} else {
|
||||||
|
// do not implicitly load core vocabularies any more. But if the
|
||||||
|
// references loading the core vocabularies try to use local if we can
|
||||||
|
refProvider = buildEdmProvider(is, resolver, false, useLocal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CsdlSchema refSchema = refProvider.getSchema(include.getNamespace(), false);
|
||||||
|
provider.addReferenceSchema(include.getNamespace(), refProvider);
|
||||||
|
if (include.getAlias() != null) {
|
||||||
|
refSchema.setAlias(include.getAlias());
|
||||||
|
provider.addReferenceSchema(include.getAlias(), refProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
throw new EdmException("Failed to load Reference "+reference.getUri()+" parsing failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCoreVocabulary(SchemaBasedEdmProvider provider,
|
||||||
|
String namespace) throws XMLStreamException {
|
||||||
|
if(namespace.equalsIgnoreCase("Org.OData.Core.V1")) {
|
||||||
|
loadLocalVocabularySchema(provider, "Org.OData.Core.V1", "Org.OData.Core.V1.xml");
|
||||||
|
} else if (namespace.equalsIgnoreCase("Org.OData.Capabilities.V1")) {
|
||||||
|
loadLocalVocabularySchema(provider, "Org.OData.Capabilities.V1", "Org.OData.Capabilities.V1.xml");
|
||||||
|
} else if (namespace.equalsIgnoreCase("Org.OData.Measures.V1")) {
|
||||||
|
loadLocalVocabularySchema(provider, "Org.OData.Measures.V1", "Org.OData.Measures.V1.xml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCoreVocabulary(String namespace) {
|
||||||
|
if(namespace.equalsIgnoreCase("Org.OData.Core.V1") ||
|
||||||
|
namespace.equalsIgnoreCase("Org.OData.Capabilities.V1") ||
|
||||||
|
namespace.equalsIgnoreCase("Org.OData.Measures.V1")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fixXmlBase(String base) {
|
||||||
|
if (base.endsWith("/")) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
return base+"/";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadLocalVocabularySchema(SchemaBasedEdmProvider provider, String namespace,
|
||||||
String resource) throws XMLStreamException {
|
String resource) throws XMLStreamException {
|
||||||
CsdlSchema schema = provider.getSchema(namespace, false);
|
CsdlSchema schema = provider.getVocabularySchema(namespace);
|
||||||
if (schema == null) {
|
if (schema == null) {
|
||||||
InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
|
InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false);
|
SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false);
|
||||||
provider.addSchema(childProvider.getSchema(namespace, false));
|
provider.addVocabularySchema(namespace, childProvider);
|
||||||
} else {
|
} else {
|
||||||
throw new XMLStreamException("failed to load "+resource+" core vocabulary");
|
throw new XMLStreamException("failed to load "+resource+" core vocabulary");
|
||||||
}
|
}
|
||||||
@ -191,7 +304,8 @@ public class MetadataParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readDataServicesAndReference(XMLEventReader reader,
|
private void readDataServicesAndReference(XMLEventReader reader,
|
||||||
StartElement element, SchemaBasedEdmProvider provider) throws XMLStreamException {
|
StartElement element, SchemaBasedEdmProvider provider)
|
||||||
|
throws XMLStreamException {
|
||||||
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
|
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
|
||||||
new ElementReader<SchemaBasedEdmProvider>() {
|
new ElementReader<SchemaBasedEdmProvider>() {
|
||||||
@Override
|
@Override
|
||||||
@ -384,7 +498,9 @@ public class MetadataParser {
|
|||||||
CsdlTypeDefinition td = new CsdlTypeDefinition();
|
CsdlTypeDefinition td = new CsdlTypeDefinition();
|
||||||
td.setName(attr(element, "Name"));
|
td.setName(attr(element, "Name"));
|
||||||
td.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
|
td.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
|
||||||
|
if (attr(element, "Unicode") != null) {
|
||||||
td.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
td.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
||||||
|
}
|
||||||
|
|
||||||
String maxLength = attr(element, "MaxLength");
|
String maxLength = attr(element, "MaxLength");
|
||||||
if (maxLength != null) {
|
if (maxLength != null) {
|
||||||
@ -837,7 +953,9 @@ public class MetadataParser {
|
|||||||
property.setCollection(isCollectionType(element));
|
property.setCollection(isCollectionType(element));
|
||||||
property.setNullable(Boolean.parseBoolean(attr(element, "Nullable") == null ? "true" : attr(
|
property.setNullable(Boolean.parseBoolean(attr(element, "Nullable") == null ? "true" : attr(
|
||||||
element, "Nullable")));
|
element, "Nullable")));
|
||||||
|
if (attr(element, "Unicode") != null) {
|
||||||
property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
||||||
|
}
|
||||||
|
|
||||||
String maxLength = attr(element, "MaxLength");
|
String maxLength = attr(element, "MaxLength");
|
||||||
if (maxLength != null) {
|
if (maxLength != null) {
|
||||||
@ -1077,18 +1195,23 @@ public class MetadataParser {
|
|||||||
private static class DefaultReferenceResolver implements ReferenceResolver {
|
private static class DefaultReferenceResolver implements ReferenceResolver {
|
||||||
@Override
|
@Override
|
||||||
public InputStream resolveReference(URI referenceUri, String xmlBase) {
|
public InputStream resolveReference(URI referenceUri, String xmlBase) {
|
||||||
URL schemaURL = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
if (referenceUri.isAbsolute()) {
|
if (referenceUri.isAbsolute()) {
|
||||||
schemaURL = referenceUri.toURL();
|
URL schemaURL = referenceUri.toURL();
|
||||||
|
in = schemaURL.openStream();
|
||||||
} else {
|
} else {
|
||||||
if (xmlBase != null) {
|
if (xmlBase != null) {
|
||||||
schemaURL = new URL(xmlBase+referenceUri.toString());
|
URL schemaURL = new URL(xmlBase+referenceUri.toString());
|
||||||
|
in = schemaURL.openStream();
|
||||||
} else {
|
} else {
|
||||||
|
in = this.getClass().getClassLoader().getResourceAsStream(referenceUri.getPath());
|
||||||
|
if (in == null) {
|
||||||
throw new EdmException("No xml:base set to read the references from the metadata");
|
throw new EdmException("No xml:base set to read the references from the metadata");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return schemaURL.openStream();
|
}
|
||||||
|
return in;
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
throw new EdmException(e);
|
throw new EdmException(e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -18,15 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.olingo.server.core;
|
package org.apache.olingo.server.core;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmException;
|
|
||||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
|
import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
|
||||||
@ -52,14 +48,10 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
|
|||||||
public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
||||||
private final List<CsdlSchema> edmSchemas = new ArrayList<CsdlSchema>();
|
private final List<CsdlSchema> edmSchemas = new ArrayList<CsdlSchema>();
|
||||||
private final Map<String, EdmxReference> references = new ConcurrentHashMap<String, EdmxReference>();
|
private final Map<String, EdmxReference> references = new ConcurrentHashMap<String, EdmxReference>();
|
||||||
private final Map<String, SchemaBasedEdmProvider> referenceSchemas
|
private final Map<String, SchemaBasedEdmProvider> referenceSchemas =
|
||||||
= new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
|
new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
|
||||||
private String xmlBase;
|
private final Map<String, SchemaBasedEdmProvider> coreVocabularySchemas =
|
||||||
private ReferenceResolver referenceResolver;
|
new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
|
||||||
|
|
||||||
public SchemaBasedEdmProvider(ReferenceResolver referenceResolver) {
|
|
||||||
this.referenceResolver = referenceResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addSchema(CsdlSchema schema) {
|
void addSchema(CsdlSchema schema) {
|
||||||
this.edmSchemas.add(schema);
|
this.edmSchemas.add(schema);
|
||||||
@ -69,6 +61,22 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||||||
return new ArrayList<EdmxReference>(references.values());
|
return new ArrayList<EdmxReference>(references.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addReferenceSchema(String ns, SchemaBasedEdmProvider provider) {
|
||||||
|
this.referenceSchemas.put(ns, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addVocabularySchema(String ns, SchemaBasedEdmProvider provider) {
|
||||||
|
this.coreVocabularySchemas.put(ns, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
CsdlSchema getVocabularySchema(String ns) {
|
||||||
|
SchemaBasedEdmProvider provider = this.coreVocabularySchemas.get(ns);
|
||||||
|
if (provider != null) {
|
||||||
|
return provider.getSchema(ns, false);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
CsdlSchema getSchema(String ns) {
|
CsdlSchema getSchema(String ns) {
|
||||||
return getSchema(ns, true);
|
return getSchema(ns, true);
|
||||||
}
|
}
|
||||||
@ -79,46 +87,20 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CsdlSchema s = null;
|
||||||
if (checkReferences) {
|
if (checkReferences) {
|
||||||
return getReferenceSchema(ns);
|
s = getReferenceSchema(ns);
|
||||||
|
if (s == null) {
|
||||||
|
s = getVocabularySchema(ns);
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CsdlSchema getReferenceSchema(String ns) {
|
CsdlSchema getReferenceSchema(String ns) {
|
||||||
if (ns == null) {
|
if (ns == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (this.referenceSchemas.get(ns) == null) {
|
|
||||||
EdmxReference reference = this.references.get(ns);
|
|
||||||
if (reference != null) {
|
|
||||||
SchemaBasedEdmProvider provider = null;
|
|
||||||
if (this.referenceResolver == null) {
|
|
||||||
throw new EdmException("Failed to load Reference "+reference.getUri());
|
|
||||||
} else {
|
|
||||||
InputStream is = this.referenceResolver.resolveReference(reference.getUri(), this.xmlBase);
|
|
||||||
if (is != null) {
|
|
||||||
try {
|
|
||||||
MetadataParser parser = new MetadataParser();
|
|
||||||
provider = parser.buildEdmProvider(is, this.referenceResolver, false);
|
|
||||||
} catch (XMLStreamException e) {
|
|
||||||
throw new EdmException("Failed to load Reference "+reference.getUri()+" parsing failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new EdmException("Failed to load Reference "+reference.getUri()+" loading failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// copy references
|
|
||||||
for (EdmxReferenceInclude include : reference.getIncludes()) {
|
|
||||||
this.referenceSchemas.put(include.getNamespace(), provider);
|
|
||||||
if (include.getAlias() != null) {
|
|
||||||
CsdlSchema schema = provider.getSchema(include.getNamespace());
|
|
||||||
schema.setAlias(include.getAlias());
|
|
||||||
this.referenceSchemas.put(include.getAlias(), provider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.referenceSchemas.get(ns) != null) {
|
if (this.referenceSchemas.get(ns) != null) {
|
||||||
return this.referenceSchemas.get(ns).getSchema(ns);
|
return this.referenceSchemas.get(ns).getSchema(ns);
|
||||||
@ -403,14 +385,4 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setXMLBase(String base) {
|
|
||||||
if (base != null) {
|
|
||||||
if (base.endsWith("/")) {
|
|
||||||
this.xmlBase = base;
|
|
||||||
} else {
|
|
||||||
this.xmlBase = base+"/";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,18 @@ import java.util.Map;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.data.ContextURL;
|
import org.apache.olingo.commons.api.data.ContextURL;
|
||||||
|
import org.apache.olingo.commons.api.edm.EdmAnnotation;
|
||||||
|
import org.apache.olingo.commons.api.edm.EdmSchema;
|
||||||
|
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||||
|
import org.apache.olingo.commons.api.edm.annotation.EdmConstantExpression;
|
||||||
import org.apache.olingo.commons.api.format.ContentType;
|
import org.apache.olingo.commons.api.format.ContentType;
|
||||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||||
import org.apache.olingo.server.api.OData;
|
import org.apache.olingo.server.api.OData;
|
||||||
import org.apache.olingo.server.api.ODataApplicationException;
|
import org.apache.olingo.server.api.ODataApplicationException;
|
||||||
|
import org.apache.olingo.server.api.ODataLibraryException;
|
||||||
import org.apache.olingo.server.api.ODataRequest;
|
import org.apache.olingo.server.api.ODataRequest;
|
||||||
import org.apache.olingo.server.api.ODataResponse;
|
import org.apache.olingo.server.api.ODataResponse;
|
||||||
import org.apache.olingo.server.api.ODataLibraryException;
|
|
||||||
import org.apache.olingo.server.api.ServiceMetadata;
|
import org.apache.olingo.server.api.ServiceMetadata;
|
||||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||||
@ -140,26 +144,60 @@ public abstract class ServiceRequest {
|
|||||||
return this.request.getMethod() == HttpMethod.POST;
|
return this.request.getMethod() == HttpMethod.POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FullQualifiedName XML10_CHAR_REPLACE_FQN = new FullQualifiedName(
|
||||||
|
"org.apache.olingo.v1.xml10-incompatible-char-replacement");
|
||||||
|
/**
|
||||||
|
* Replacement character for the XML10 characters that are not supported.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String xml10IncompatibleCharReplacement() {
|
||||||
|
for (EdmSchema schema : getServiceMetaData().getEdm().getSchemas()) {
|
||||||
|
if (schema.getEntityContainer() != null) {
|
||||||
|
for (EdmAnnotation annotation:schema.getAnnotations()) {
|
||||||
|
if (annotation.getTerm() != null
|
||||||
|
&& annotation.getTerm().getFullQualifiedName().equals(XML10_CHAR_REPLACE_FQN)) {
|
||||||
|
EdmConstantExpression expr = annotation.getExpression().asConstant();
|
||||||
|
return expr.getValueAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl,
|
public <T> T getSerializerOptions(Class<T> serilizerOptions,
|
||||||
boolean references) throws ContentNegotiatorException {
|
ContextURL contextUrl, boolean references) throws ContentNegotiatorException {
|
||||||
|
|
||||||
|
String xmlReplacement = null;
|
||||||
|
if (getResponseContentType().isCompatible(ContentType.APPLICATION_XML)
|
||||||
|
|| getResponseContentType().isCompatible(ContentType.APPLICATION_ATOM_XML)) {
|
||||||
|
xmlReplacement = xml10IncompatibleCharReplacement();
|
||||||
|
}
|
||||||
|
|
||||||
if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
|
if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
|
||||||
return (T) EntitySerializerOptions.with()
|
return (T) EntitySerializerOptions.with()
|
||||||
.contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
|
.contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
|
||||||
.expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
|
.expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
|
||||||
.writeOnlyReferences(references).build();
|
.writeOnlyReferences(references)
|
||||||
|
.xml10InvalidCharReplacement(xmlReplacement)
|
||||||
|
.build();
|
||||||
} else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
|
} else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
|
||||||
return (T) EntityCollectionSerializerOptions.with()
|
return (T) EntityCollectionSerializerOptions.with()
|
||||||
.contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
|
.contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
|
||||||
.count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
|
.count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
|
||||||
.select(uriInfo.getSelectOption()).writeOnlyReferences(references)
|
.select(uriInfo.getSelectOption()).writeOnlyReferences(references)
|
||||||
.id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath()).build();
|
.id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath())
|
||||||
|
.xml10InvalidCharReplacement(xmlReplacement)
|
||||||
|
.build();
|
||||||
} else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
|
} else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
|
||||||
return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
|
return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
|
||||||
.expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()).build();
|
.expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
|
||||||
|
.xml10InvalidCharReplacement(xmlReplacement)
|
||||||
|
.build();
|
||||||
} else if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
|
} else if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
|
||||||
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
|
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
|
||||||
|
.xml10InvalidCharReplacement(xmlReplacement)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -250,8 +250,17 @@ public class DataRequest extends ServiceRequest {
|
|||||||
public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references)
|
public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references)
|
||||||
throws ContentNegotiatorException {
|
throws ContentNegotiatorException {
|
||||||
if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
|
if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
|
||||||
|
|
||||||
|
String xmlReplacement = null;
|
||||||
|
if (getResponseContentType().isCompatible(ContentType.APPLICATION_XML)
|
||||||
|
|| getResponseContentType().isCompatible(ContentType.APPLICATION_ATOM_XML)) {
|
||||||
|
xmlReplacement = xml10IncompatibleCharReplacement();
|
||||||
|
}
|
||||||
|
|
||||||
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
|
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
|
||||||
.facetsFrom(getUriResourceProperty().getProperty()).build();
|
.facetsFrom(getUriResourceProperty().getProperty())
|
||||||
|
.xml10InvalidCharReplacement(xmlReplacement)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
return super.getSerializerOptions(serilizerOptions, contextUrl, references);
|
return super.getSerializerOptions(serilizerOptions, contextUrl, references);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
|
||||||
|
<edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
|
||||||
|
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
|
||||||
|
</edmx:Reference>
|
||||||
|
<edmx:DataServices>
|
||||||
|
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="org.apache.olingo.v1" Alias="olingo-extensions">
|
||||||
|
|
||||||
|
<Term Name="xml10-incompatible-char-replacement" Type="Edm.String" AppliesTo="PropertyValue ReturnType">
|
||||||
|
<Annotation Term="Core.Description">
|
||||||
|
<String>
|
||||||
|
Replacement character for invalid characters in the XML 1.0 Atom payload
|
||||||
|
</String>
|
||||||
|
</Annotation>
|
||||||
|
</Term>
|
||||||
|
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
@ -60,7 +60,7 @@ public class MetadataParserAnnotationsTest {
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MetadataParser parser = new MetadataParser();
|
MetadataParser parser = new MetadataParser();
|
||||||
parser.parseAnnotations(true);
|
parser.parseAnnotations(true);
|
||||||
parser.loadCoreVocabularies(true);
|
parser.useLocalCoreVocabularies(true);
|
||||||
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/annotations.xml"));
|
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/annotations.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ public class MetadataParserTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MetadataParser parser = new MetadataParser();
|
MetadataParser parser = new MetadataParser();
|
||||||
parser.parseAnnotations(true);
|
|
||||||
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
|
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,9 @@ public class ServiceDispatcherTest {
|
|||||||
|
|
||||||
public void beforeTest(ServiceHandler serviceHandler) throws Exception {
|
public void beforeTest(ServiceHandler serviceHandler) throws Exception {
|
||||||
MetadataParser parser = new MetadataParser();
|
MetadataParser parser = new MetadataParser();
|
||||||
|
parser.parseAnnotations(true);
|
||||||
|
parser.useLocalCoreVocabularies(true);
|
||||||
|
parser.implicitlyLoadCoreVocabularies(true);
|
||||||
ServiceMetadata metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
|
ServiceMetadata metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
|
||||||
|
|
||||||
File baseDir = new File(System.getProperty("java.io.tmpdir"));
|
File baseDir = new File(System.getProperty("java.io.tmpdir"));
|
||||||
|
@ -114,18 +114,21 @@ public class TripPinServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEntitySet() throws Exception {
|
public void testXMLInvalidChars() throws Exception {
|
||||||
HttpRequest req = new HttpGet(baseURL+"/People");
|
HttpRequest req = new HttpGet(baseURL+"/Airlines('FM')");
|
||||||
req.setHeader("Content-Type", "application/json;odata.metadata=minimal");
|
req.setHeader("Accept", "application/xml");
|
||||||
|
|
||||||
HttpResponse response = httpSend(req, 200);
|
HttpResponse response = httpSend(req, 200);
|
||||||
JsonNode node = getJSONNode(response);
|
String actual = IOUtils.toString(response.getEntity().getContent());
|
||||||
|
String expected =
|
||||||
assertEquals("$metadata#People", node.get("@odata.context").asText());
|
"<m:properties>"
|
||||||
assertEquals(baseURL+"/People?$skiptoken=8", node.get("@odata.nextLink").asText());
|
+ "<d:AirlineCode>FM</d:AirlineCode>"
|
||||||
|
+ "<d:Name>Shanghai xxxAirlinexxx</d:Name>"
|
||||||
JsonNode person = ((ArrayNode)node.get("value")).get(0);
|
+ "<d:Picture m:null=\"true\"/>"
|
||||||
assertEquals("russellwhyte", person.get("UserName").asText());
|
+ "</m:properties>"
|
||||||
|
+ "</a:content>"
|
||||||
|
+"</a:entry>";
|
||||||
|
assertTrue(actual.endsWith(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -51,7 +51,8 @@ public class TripPinServlet extends HttpServlet {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
parser.parseAnnotations(true);
|
parser.parseAnnotations(true);
|
||||||
parser.loadCoreVocabularies(true);
|
parser.useLocalCoreVocabularies(true);
|
||||||
|
parser.implicitlyLoadCoreVocabularies(true);
|
||||||
metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
|
metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
|
||||||
} catch (XMLStreamException e) {
|
} catch (XMLStreamException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AirlineCode":"FM",
|
"AirlineCode":"FM",
|
||||||
"Name":"Shanghai Airline"
|
"Name":"Shanghai \u0000Airline\u0001"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"AirlineCode":"MU",
|
"AirlineCode":"MU",
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
language governing permissions and limitations under the License. -->
|
language governing permissions and limitations under the License. -->
|
||||||
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
|
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
|
||||||
Version="4.0">
|
Version="4.0">
|
||||||
|
<edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
|
||||||
|
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
|
||||||
|
</edmx:Reference>
|
||||||
<edmx:DataServices>
|
<edmx:DataServices>
|
||||||
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm"
|
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm"
|
||||||
Namespace="Org.OData.AnnoatationTest" Alias="test">
|
Namespace="Org.OData.AnnoatationTest" Alias="test">
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
OF ANY KIND, either express or implied. See the License for the specific
|
OF ANY KIND, either express or implied. See the License for the specific
|
||||||
language governing permissions and limitations under the License. -->
|
language governing permissions and limitations under the License. -->
|
||||||
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||||
|
<edmx:Reference Uri="org.apache.olingo.v1.xml">
|
||||||
|
<edmx:Include Alias="olingo-extensions" Namespace="org.apache.olingo.v1" />
|
||||||
|
</edmx:Reference>
|
||||||
<edmx:DataServices>
|
<edmx:DataServices>
|
||||||
<Schema Namespace="Microsoft.OData.SampleService.Models.TripPin"
|
<Schema Namespace="Microsoft.OData.SampleService.Models.TripPin"
|
||||||
xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||||
@ -103,7 +106,7 @@
|
|||||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
</Annotation>
|
</Annotation>
|
||||||
</Property>
|
</Property>
|
||||||
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
<Property Name="Name" Type="Edm.String" Nullable="false"/>
|
||||||
<Property Name="IataCode" Type="Edm.String" Nullable="false">
|
<Property Name="IataCode" Type="Edm.String" Nullable="false">
|
||||||
<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true" />
|
<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true" />
|
||||||
</Property>
|
</Property>
|
||||||
@ -453,6 +456,7 @@
|
|||||||
</Annotation>
|
</Annotation>
|
||||||
<Annotation Term="Core.RequiresType" String="Edm.String" />
|
<Annotation Term="Core.RequiresType" String="Edm.String" />
|
||||||
</Term>
|
</Term>
|
||||||
|
<Annotation Term="org.apache.olingo.v1.xml10-incompatible-char-replacement" String="xxx"/>
|
||||||
</Schema>
|
</Schema>
|
||||||
</edmx:DataServices>
|
</edmx:DataServices>
|
||||||
</edmx:Edmx>
|
</edmx:Edmx>
|
@ -52,6 +52,7 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
|||||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||||
import org.apache.olingo.commons.api.ex.ODataErrorDetail;
|
import org.apache.olingo.commons.api.ex.ODataErrorDetail;
|
||||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||||
|
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
|
||||||
import org.apache.olingo.server.api.ODataServerError;
|
import org.apache.olingo.server.api.ODataServerError;
|
||||||
import org.apache.olingo.server.api.ServiceMetadata;
|
import org.apache.olingo.server.api.ServiceMetadata;
|
||||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||||
@ -250,10 +251,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
writeEntitySet(metadata, entityType, entitySet, null, null, writer);
|
writeEntitySet(metadata, entityType, entitySet, null, null, null, writer);
|
||||||
} else {
|
} else {
|
||||||
writeEntitySet(metadata, entityType, entitySet,
|
writeEntitySet(metadata, entityType, entitySet,
|
||||||
options.getExpand(), options.getSelect(), writer);
|
options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
@ -296,7 +297,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
|
writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
|
||||||
writeEntity(metadata, entityType, entity, contextURL,
|
writeEntity(metadata, entityType, entity, contextURL,
|
||||||
options == null ? null : options.getExpand(),
|
options == null ? null : options.getExpand(),
|
||||||
options == null ? null : options.getSelect(), writer, true);
|
options == null ? null : options.getSelect(),
|
||||||
|
options == null ? null : options.xml10InvalidCharReplacement(),
|
||||||
|
writer, true);
|
||||||
writer.writeEndDocument();
|
writer.writeEndDocument();
|
||||||
|
|
||||||
writer.flush();
|
writer.flush();
|
||||||
@ -336,15 +339,17 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
|
|
||||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||||
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||||
final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
|
final String xml10InvalidCharReplacement,final XMLStreamWriter writer)
|
||||||
|
throws XMLStreamException, SerializerException {
|
||||||
for (final Entity entity : entitySet.getEntities()) {
|
for (final Entity entity : entitySet.getEntities()) {
|
||||||
writeEntity(metadata, entityType, entity, null, expand, select, writer, false);
|
writeEntity(metadata, entityType, entity, null, expand, select, xml10InvalidCharReplacement, writer, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||||
final Entity entity, final ContextURL contextURL, final ExpandOption expand,
|
final Entity entity, final ContextURL contextURL, final ExpandOption expand,
|
||||||
final SelectOption select, final XMLStreamWriter writer, final boolean top)
|
final SelectOption select, final String xml10InvalidCharReplacement,
|
||||||
|
final XMLStreamWriter writer, final boolean top)
|
||||||
throws XMLStreamException, SerializerException {
|
throws XMLStreamException, SerializerException {
|
||||||
|
|
||||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ENTRY, NS_ATOM);
|
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ENTRY, NS_ATOM);
|
||||||
@ -397,7 +402,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
|
EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
|
||||||
writeNavigationProperties(metadata, resolvedType, entity, expand, writer);
|
writeNavigationProperties(metadata, resolvedType, entity, expand, xml10InvalidCharReplacement, writer);
|
||||||
|
|
||||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM);
|
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM);
|
||||||
writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
|
writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
|
||||||
@ -412,7 +417,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writer.writeStartElement(METADATA, Constants.PROPERTIES, NS_METADATA);
|
writer.writeStartElement(METADATA, Constants.PROPERTIES, NS_METADATA);
|
||||||
writeProperties(metadata, resolvedType, entity.getProperties(), select, writer);
|
writeProperties(metadata, resolvedType, entity.getProperties(), select, xml10InvalidCharReplacement, writer);
|
||||||
writer.writeEndElement(); // properties
|
writer.writeEndElement(); // properties
|
||||||
|
|
||||||
if (!entityType.hasStream()) { // content
|
if (!entityType.hasStream()) { // content
|
||||||
@ -490,8 +495,8 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
|
protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
|
||||||
final List<Property> properties, final SelectOption select, final XMLStreamWriter writer)
|
final List<Property> properties, final SelectOption select, final String xml10InvalidCharReplacement,
|
||||||
throws XMLStreamException, SerializerException {
|
final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
|
||||||
final boolean all = ExpandSelectHelper.isAll(select);
|
final boolean all = ExpandSelectHelper.isAll(select);
|
||||||
final Set<String> selected = all ? new HashSet<String>() :
|
final Set<String> selected = all ? new HashSet<String>() :
|
||||||
ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
|
ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
|
||||||
@ -501,14 +506,15 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
final Property property = findProperty(propertyName, properties);
|
final Property property = findProperty(propertyName, properties);
|
||||||
final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
|
final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null :
|
||||||
ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
|
ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), propertyName);
|
||||||
writeProperty(metadata, edmProperty, property, selectedPaths, writer);
|
writeProperty(metadata, edmProperty, property, selectedPaths, xml10InvalidCharReplacement, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeNavigationProperties(final ServiceMetadata metadata,
|
protected void writeNavigationProperties(final ServiceMetadata metadata,
|
||||||
final EdmStructuredType type, final Linked linked, final ExpandOption expand,
|
final EdmStructuredType type, final Linked linked, final ExpandOption expand,
|
||||||
final XMLStreamWriter writer) throws SerializerException, XMLStreamException {
|
final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
|
throws SerializerException, XMLStreamException {
|
||||||
if (ExpandSelectHelper.hasExpand(expand)) {
|
if (ExpandSelectHelper.hasExpand(expand)) {
|
||||||
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
|
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
|
||||||
final Set<String> expanded = expandAll ? new HashSet<String>() :
|
final Set<String> expanded = expandAll ? new HashSet<String>() :
|
||||||
@ -529,7 +535,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
||||||
innerOptions == null ? null : innerOptions.getExpandOption(),
|
innerOptions == null ? null : innerOptions.getExpandOption(),
|
||||||
innerOptions == null ? null : innerOptions.getSelectOption(),
|
innerOptions == null ? null : innerOptions.getSelectOption(),
|
||||||
writer);
|
xml10InvalidCharReplacement, writer);
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
}
|
}
|
||||||
@ -588,27 +594,28 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
|
|
||||||
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
|
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
|
||||||
final EdmNavigationProperty property, final Link navigationLink,
|
final EdmNavigationProperty property, final Link navigationLink,
|
||||||
final ExpandOption innerExpand, final SelectOption innerSelect, final XMLStreamWriter writer)
|
final ExpandOption innerExpand, final SelectOption innerSelect, final String xml10InvalidCharReplacement,
|
||||||
throws XMLStreamException, SerializerException {
|
final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
|
||||||
if (property.isCollection()) {
|
if (property.isCollection()) {
|
||||||
if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
|
if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
|
||||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_FEED, NS_ATOM);
|
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_FEED, NS_ATOM);
|
||||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||||
innerSelect, writer);
|
innerSelect, xml10InvalidCharReplacement, writer);
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (navigationLink != null && navigationLink.getInlineEntity() != null) {
|
if (navigationLink != null && navigationLink.getInlineEntity() != null) {
|
||||||
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
|
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
|
||||||
innerExpand, innerSelect, writer, false);
|
innerExpand, innerSelect, xml10InvalidCharReplacement, writer, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty,
|
protected void writeProperty(final ServiceMetadata metadata,
|
||||||
final Property property,
|
final EdmProperty edmProperty, final Property property,
|
||||||
final Set<List<String>> selectedPaths, final XMLStreamWriter writer) throws XMLStreamException,
|
final Set<List<String>> selectedPaths,
|
||||||
SerializerException {
|
final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
|
throws XMLStreamException, SerializerException {
|
||||||
writer.writeStartElement(DATA, edmProperty.getName(), NS_DATA);
|
writer.writeStartElement(DATA, edmProperty.getName(), NS_DATA);
|
||||||
if (property == null || property.isNull()) {
|
if (property == null || property.isNull()) {
|
||||||
if (edmProperty.isNullable()) {
|
if (edmProperty.isNullable()) {
|
||||||
@ -618,7 +625,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
|
SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writePropertyValue(metadata, edmProperty, property, selectedPaths, writer);
|
writePropertyValue(metadata, edmProperty, property, selectedPaths, xml10InvalidCharReplacement, writer);
|
||||||
}
|
}
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
}
|
}
|
||||||
@ -642,9 +649,11 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
return definedType;
|
return definedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
|
private void writePropertyValue(final ServiceMetadata metadata,
|
||||||
final Property property, final Set<List<String>> selectedPaths,
|
final EdmProperty edmProperty, final Property property,
|
||||||
final XMLStreamWriter writer) throws XMLStreamException, SerializerException {
|
final Set<List<String>> selectedPaths,
|
||||||
|
final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
|
throws XMLStreamException, SerializerException {
|
||||||
try {
|
try {
|
||||||
if (edmProperty.isPrimitive()
|
if (edmProperty.isPrimitive()
|
||||||
|| edmProperty.getType().getKind() == EdmTypeKind.ENUM
|
|| edmProperty.getType().getKind() == EdmTypeKind.ENUM
|
||||||
@ -657,22 +666,23 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
|
writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
|
||||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
|
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
|
||||||
writer);
|
xml10InvalidCharReplacement,writer);
|
||||||
} else {
|
} else {
|
||||||
writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
|
writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
|
||||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
|
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
|
||||||
writer);
|
xml10InvalidCharReplacement, writer);
|
||||||
}
|
}
|
||||||
} else if (property.isComplex()) {
|
} else if (property.isComplex()) {
|
||||||
if (edmProperty.isCollection()) {
|
if (edmProperty.isCollection()) {
|
||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE, collectionType(edmProperty.getType()));
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE, collectionType(edmProperty.getType()));
|
||||||
writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths, writer);
|
writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths,
|
||||||
|
xml10InvalidCharReplacement, writer);
|
||||||
} else {
|
} else {
|
||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
|
||||||
"#" + complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
|
"#" + complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
|
||||||
writeComplexValue(metadata, property, (EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
|
writeComplexValue(metadata, property, (EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
|
||||||
selectedPaths, writer);
|
selectedPaths, xml10InvalidCharReplacement, writer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new SerializerException("Property type not yet supported!",
|
throw new SerializerException("Property type not yet supported!",
|
||||||
@ -687,14 +697,15 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
|
|
||||||
private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
|
private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||||
final Boolean isUnicode,
|
final Boolean isUnicode, final String xml10InvalidCharReplacement,
|
||||||
final XMLStreamWriter writer) throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
|
final XMLStreamWriter writer) throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
|
||||||
for (Object value : property.asCollection()) {
|
for (Object value : property.asCollection()) {
|
||||||
writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
|
writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
|
||||||
switch (property.getValueType()) {
|
switch (property.getValueType()) {
|
||||||
case COLLECTION_PRIMITIVE:
|
case COLLECTION_PRIMITIVE:
|
||||||
case COLLECTION_ENUM:
|
case COLLECTION_ENUM:
|
||||||
writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, writer);
|
writePrimitiveValue(type, value, isNullable, maxLength, precision,
|
||||||
|
scale, isUnicode, xml10InvalidCharReplacement, writer);
|
||||||
break;
|
break;
|
||||||
case COLLECTION_GEOSPATIAL:
|
case COLLECTION_GEOSPATIAL:
|
||||||
throw new SerializerException("Property type not yet supported!",
|
throw new SerializerException("Property type not yet supported!",
|
||||||
@ -707,8 +718,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
|
private void writeComplexCollection(final ServiceMetadata metadata,
|
||||||
final Property property, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
|
final EdmComplexType type, final Property property, final Set<List<String>> selectedPaths,
|
||||||
|
final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
throws XMLStreamException, SerializerException {
|
throws XMLStreamException, SerializerException {
|
||||||
for (Object value : property.asCollection()) {
|
for (Object value : property.asCollection()) {
|
||||||
writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
|
writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
|
||||||
@ -717,7 +729,9 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
}
|
}
|
||||||
switch (property.getValueType()) {
|
switch (property.getValueType()) {
|
||||||
case COLLECTION_COMPLEX:
|
case COLLECTION_COMPLEX:
|
||||||
writeComplexValue(metadata, property, type, ((ComplexValue) value).getValue(), selectedPaths, writer);
|
writeComplexValue(metadata, property, type,
|
||||||
|
((ComplexValue) value).getValue(), selectedPaths,
|
||||||
|
xml10InvalidCharReplacement, writer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new SerializerException("Property type not yet supported!",
|
throw new SerializerException("Property type not yet supported!",
|
||||||
@ -729,7 +743,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
|
|
||||||
private void writePrimitive(final EdmPrimitiveType type, final Property property,
|
private void writePrimitive(final EdmPrimitiveType type, final Property property,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||||
final Boolean isUnicode, final XMLStreamWriter writer)
|
final Boolean isUnicode, final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
throws EdmPrimitiveTypeException, XMLStreamException, SerializerException {
|
throws EdmPrimitiveTypeException, XMLStreamException, SerializerException {
|
||||||
if (property.isPrimitive()) {
|
if (property.isPrimitive()) {
|
||||||
if (type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String)) {
|
if (type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String)) {
|
||||||
@ -739,7 +753,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
type.getName());
|
type.getName());
|
||||||
}
|
}
|
||||||
writePrimitiveValue(type, property.asPrimitive(),
|
writePrimitiveValue(type, property.asPrimitive(),
|
||||||
isNullable, maxLength, precision, scale, isUnicode, writer);
|
isNullable, maxLength, precision, scale, isUnicode, xml10InvalidCharReplacement, writer);
|
||||||
} else if (property.isGeospatial()) {
|
} else if (property.isGeospatial()) {
|
||||||
throw new SerializerException("Property type not yet supported!",
|
throw new SerializerException("Property type not yet supported!",
|
||||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||||
@ -747,7 +761,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
|
||||||
"#" + type.getFullQualifiedName().getFullQualifiedNameAsString());
|
"#" + type.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||||
writePrimitiveValue(type, property.asEnum(),
|
writePrimitiveValue(type, property.asEnum(),
|
||||||
isNullable, maxLength, precision, scale, isUnicode, writer);
|
isNullable, maxLength, precision, scale, isUnicode, xml10InvalidCharReplacement, writer);
|
||||||
} else {
|
} else {
|
||||||
throw new SerializerException("Inconsistent property type!",
|
throw new SerializerException("Inconsistent property type!",
|
||||||
SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
|
SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
|
||||||
@ -756,19 +770,23 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
|
|
||||||
protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
|
protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||||
final Boolean isUnicode,
|
final Boolean isUnicode, final String xml10InvalidCharReplacement,
|
||||||
final XMLStreamWriter writer) throws EdmPrimitiveTypeException, XMLStreamException {
|
final XMLStreamWriter writer) throws EdmPrimitiveTypeException, XMLStreamException {
|
||||||
final String value = type.valueToString(primitiveValue,
|
final String value = type.valueToString(primitiveValue,
|
||||||
isNullable, maxLength, precision, scale, isUnicode);
|
isNullable, maxLength, precision, scale, isUnicode);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
|
||||||
} else {
|
} else {
|
||||||
writer.writeCharacters(value);
|
// XML 1.0 does not handle certain unicode characters, they need to be replaced
|
||||||
|
writer.writeCharacters(replaceInvalidCharacters(type, value,
|
||||||
|
isUnicode, xml10InvalidCharReplacement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeComplexValue(final ServiceMetadata metadata, Property complexProperty, final EdmComplexType type,
|
protected void writeComplexValue(final ServiceMetadata metadata,
|
||||||
final List<Property> properties, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
|
Property complexProperty, final EdmComplexType type,
|
||||||
|
final List<Property> properties, final Set<List<String>> selectedPaths,
|
||||||
|
final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
|
||||||
throws XMLStreamException, SerializerException {
|
throws XMLStreamException, SerializerException {
|
||||||
|
|
||||||
final EdmComplexType resolvedType = resolveComplexType(metadata,
|
final EdmComplexType resolvedType = resolveComplexType(metadata,
|
||||||
@ -779,7 +797,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
|
if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
|
||||||
writeProperty(metadata, (EdmProperty) resolvedType.getProperty(propertyName), property,
|
writeProperty(metadata, (EdmProperty) resolvedType.getProperty(propertyName), property,
|
||||||
selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
|
selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
|
||||||
writer);
|
xml10InvalidCharReplacement, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -822,6 +840,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
options == null ? null : options.getPrecision(),
|
options == null ? null : options.getPrecision(),
|
||||||
options == null ? null : options.getScale(),
|
options == null ? null : options.getScale(),
|
||||||
options == null ? null : options.isUnicode(),
|
options == null ? null : options.isUnicode(),
|
||||||
|
options == null ? null : options.xml10InvalidCharReplacement(),
|
||||||
writer);
|
writer);
|
||||||
}
|
}
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
@ -874,7 +893,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_NULL, "true");
|
||||||
} else {
|
} else {
|
||||||
final List<Property> values = property.asComplex().getValue();
|
final List<Property> values = property.asComplex().getValue();
|
||||||
writeProperties(metadata, resolvedType, values, options == null ? null : options.getSelect(), writer);
|
writeProperties(metadata, resolvedType, values,
|
||||||
|
options == null ? null : options.getSelect(),
|
||||||
|
options == null ? null : options.xml10InvalidCharReplacement(),
|
||||||
|
writer);
|
||||||
}
|
}
|
||||||
writer.writeEndDocument();
|
writer.writeEndDocument();
|
||||||
writer.flush();
|
writer.flush();
|
||||||
@ -922,6 +944,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
options == null ? null : options.getPrecision(),
|
options == null ? null : options.getPrecision(),
|
||||||
options == null ? null : options.getScale(),
|
options == null ? null : options.getScale(),
|
||||||
options == null ? null : options.isUnicode(),
|
options == null ? null : options.isUnicode(),
|
||||||
|
options == null ? null : options.xml10InvalidCharReplacement(),
|
||||||
writer);
|
writer);
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
writer.writeEndDocument();
|
writer.writeEndDocument();
|
||||||
@ -967,7 +990,8 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
|
writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
|
||||||
ContextURLBuilder.create(contextURL).toASCIIString());
|
ContextURLBuilder.create(contextURL).toASCIIString());
|
||||||
writeMetadataETag(metadata, writer);
|
writeMetadataETag(metadata, writer);
|
||||||
writeComplexCollection(metadata, type, property, null, writer);
|
writeComplexCollection(metadata, type, property, null,
|
||||||
|
options == null ? null:options.xml10InvalidCharReplacement(), writer);
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
writer.writeEndDocument();
|
writer.writeEndDocument();
|
||||||
writer.flush();
|
writer.flush();
|
||||||
@ -1104,4 +1128,30 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||||||
writer.writeAttribute(Constants.ATTR_HREF, entitySet.getNext().toASCIIString());
|
writer.writeAttribute(Constants.ATTR_HREF, entitySet.getNext().toASCIIString());
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String replaceInvalidCharacters(EdmPrimitiveType expectedType,
|
||||||
|
String value, Boolean isUniCode, String invalidCharacterReplacement) {
|
||||||
|
if (!(expectedType instanceof EdmString)
|
||||||
|
|| invalidCharacterReplacement == null || isUniCode == null || !isUniCode) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
String s = (String) value;
|
||||||
|
StringBuilder result = null;
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
char c = s.charAt(i);
|
||||||
|
if (c <= 0x0020 && c != ' ' && c != '\n' && c != '\t' && c != '\r') {
|
||||||
|
if (result == null) {
|
||||||
|
result = new StringBuilder();
|
||||||
|
result.append(s.substring(0, i));
|
||||||
|
}
|
||||||
|
result.append(invalidCharacterReplacement);
|
||||||
|
} else if (result != null) {
|
||||||
|
result.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1795,6 +1795,30 @@ public class ODataXmlSerializerTest {
|
|||||||
Assert.assertEquals(expected, resultString);
|
Assert.assertEquals(expected, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testXML10ReplacementChar() throws Exception {
|
||||||
|
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||||
|
final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
|
||||||
|
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
|
||||||
|
property.setValue(ValueType.PRIMITIVE, "ab\u0000cd\u0001");
|
||||||
|
final String resultString = IOUtils.toString(serializer
|
||||||
|
.primitive(metadata, (EdmPrimitiveType) edmProperty.getType(), property,
|
||||||
|
PrimitiveSerializerOptions.with()
|
||||||
|
.contextURL(ContextURL.with()
|
||||||
|
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
|
||||||
|
.build())
|
||||||
|
.xml10InvalidCharReplacement("XX")
|
||||||
|
.unicode(Boolean.TRUE)
|
||||||
|
.build()).getContent());
|
||||||
|
|
||||||
|
String expected = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||||
|
+ "<m:value xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\" "
|
||||||
|
+ "m:context=\"$metadata#ESAllPrim(32767)/PropertyString\" "
|
||||||
|
+ "m:metadata-etag=\"metadataETag\">"
|
||||||
|
+ "abXXcdXX</m:value>";
|
||||||
|
Assert.assertEquals(expected, resultString);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void primitivePropertyNull() throws Exception {
|
public void primitivePropertyNull() throws Exception {
|
||||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||||
@ -1966,8 +1990,7 @@ public class ODataXmlSerializerTest {
|
|||||||
XMLAssert.assertXMLEqual(diff, true);
|
XMLAssert.assertXMLEqual(diff, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CustomDifferenceListener implements DifferenceListener {
|
public static class CustomDifferenceListener implements DifferenceListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int differenceFound(Difference difference) {
|
public int differenceFound(Difference difference) {
|
||||||
final String xpath = "/updated[1]/text()[1]";
|
final String xpath = "/updated[1]/text()[1]";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user