[OLINGO-558] Introduce EdmMapping for deserialization

This commit is contained in:
Christian Amend 2015-02-06 14:12:23 +01:00
parent 6c74d3fee5
commit b7d2c5f441
6 changed files with 264 additions and 181 deletions

View File

@ -24,9 +24,9 @@ package org.apache.olingo.commons.api.edm;
public interface EdmMappable {
/**
* Get mapping information applied to an EDM element
* Get mapping information applied to an EDM element. May return null if no mapping is defined.
*
* @return {@link EdmMapping}
* @return {@link EdmMapping} or <b>null</b> if no mapping is defined
*/
EdmMapping getMapping();
}

View File

@ -24,30 +24,9 @@ package org.apache.olingo.commons.api.edm;
public interface EdmMapping {
/**
* Get the mapping value
*
* @return mapping name as String
* The class which is returned here will be used to during deserialization to replace the default java class for a
* primitive type.
* @return class used during deserialization
*/
String getInternalName();
/**
* Get the set object for this mapping
*
* @return {@link Object} object
*/
Object getObject();
/**
* Gets the key under which the resource source value can be found in the data map.
*
* @return the key of the media resource source
*/
String getMediaResourceSourceKey();
/**
* Gets the key under which the resource mime type can be found in the data map.
*
* @return the key of the media resource type
*/
String getMediaResourceMimeTypeKey();
Class<?> getMappedJavaClass();
}

View File

@ -19,78 +19,33 @@
package org.apache.olingo.server.api.edm.provider;
import org.apache.olingo.commons.api.edm.EdmMapping;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
/**
* Content of this class does not appear within the CSDL metadata document. This class is used to perform server
* internal mapping for edm primitive types to java types.
*/
public class Mapping implements EdmMapping {
private String value;
private Object object;
private String mediaResourceSourceKey;
private String mediaResourceMimeTypeKey;
@Override
public String getInternalName() {
return value;
}
@Override
public Object getObject() {
return object;
}
@Override
public String getMediaResourceSourceKey() {
return mediaResourceSourceKey;
}
@Override
public String getMediaResourceMimeTypeKey() {
return mediaResourceMimeTypeKey;
}
private Class<?> mappedJavaClass;
/**
* Sets the value for this {@link Mapping}.
*
* @param value
* @return {@link Mapping} for method chaining
* Sets the class to be used during deserialization to transofrm an EDM primitive type into this java class. To see
* which classes work for which primitive type refer to {@link EdmPrimitiveType}.
* @param mappedJavaClass
* @return this for method chaining
*/
public Mapping setInternalName(final String value) {
this.value = value;
public Mapping setMappedJavaClass(Class<?> mappedJavaClass) {
this.mappedJavaClass = mappedJavaClass;
return this;
}
/**
* Sets an object. This method can be used by a provider to set whatever it wants to associate with this.
*
* @param object
* @return {@link Mapping} for method chaining
/* (non-Javadoc)
* @see org.apache.olingo.commons.api.edm.EdmMapping#getMappedJavaClass()
*/
public Mapping setObject(final Object object) {
this.object = object;
return this;
@Override
public Class<?> getMappedJavaClass() {
return mappedJavaClass;
}
/**
* Sets the key for the resource source key which is used for the lookup in the data map
*
* @param mediaResourceSourceKey under which the source can be found in the data map
* @return {@link Mapping} for method chaining
*/
public Mapping setMediaResourceSourceKey(final String mediaResourceSourceKey) {
this.mediaResourceSourceKey = mediaResourceSourceKey;
return this;
}
/**
* Sets the key for the resource mime type key which is used for the lookup in the data map
*
* @param mediaResourceMimeTypeKey under which the mime type can be found in the data map
* @return {@link Mapping} for method chaining
*/
public Mapping setMediaResourceMimeTypeKey(final String mediaResourceMimeTypeKey) {
this.mediaResourceMimeTypeKey = mediaResourceMimeTypeKey;
return this;
}
}

View File

@ -472,10 +472,11 @@ public class ODataJsonDeserializer implements ODataDeserializer {
EdmTypeDefinition edmTypeDefinition = (EdmTypeDefinition) edmProperty.getType();
checkJsonTypeBasedOnPrimitiveType(edmProperty.getName(), edmTypeDefinition.getUnderlyingType().getName(),
jsonNode);
Class<?> javaClass = getJavaClassForPrimitiveType(edmProperty, edmTypeDefinition.getUnderlyingType());
return edmTypeDefinition.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
edmTypeDefinition.getMaxLength(),
edmTypeDefinition.getPrecision(), edmTypeDefinition.getScale(), edmTypeDefinition.isUnicode(),
edmTypeDefinition.getDefaultType());
javaClass);
} catch (EdmPrimitiveTypeException e) {
throw new DeserializerException(
"Invalid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
@ -504,9 +505,10 @@ public class ODataJsonDeserializer implements ODataDeserializer {
try {
EdmEnumType edmEnumType = (EdmEnumType) edmProperty.getType();
checkJsonTypeBasedOnPrimitiveType(edmProperty.getName(), edmEnumType.getUnderlyingType().getName(), jsonNode);
Class<?> javaClass = getJavaClassForPrimitiveType(edmProperty, edmEnumType.getUnderlyingType());
return edmEnumType
.valueOfString(jsonNode.asText(), edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty
.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmEnumType.getDefaultType());
.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), javaClass);
} catch (EdmPrimitiveTypeException e) {
throw new DeserializerException(
"Invalid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
@ -522,9 +524,10 @@ public class ODataJsonDeserializer implements ODataDeserializer {
try {
EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmProperty.getType();
checkJsonTypeBasedOnPrimitiveType(edmProperty.getName(), edmPrimitiveType.getName(), jsonNode);
Class<?> javaClass = getJavaClassForPrimitiveType(edmProperty, edmPrimitiveType);
return edmPrimitiveType.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
edmProperty.isUnicode(), edmPrimitiveType.getDefaultType());
edmProperty.isUnicode(), javaClass);
} catch (EdmPrimitiveTypeException e) {
throw new DeserializerException(
"Invalid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
@ -532,6 +535,24 @@ public class ODataJsonDeserializer implements ODataDeserializer {
}
}
/**
* This method either returns the primitive types default class or the manually mapped class if present.
* @param edmProperty
* @param edmPrimitiveType
* @return the java class to be used during deserialization
*/
private Class<?> getJavaClassForPrimitiveType(EdmProperty edmProperty, EdmPrimitiveType edmPrimitiveType) {
Class<?> javaClass = null;
if (edmProperty.getMapping() != null && edmProperty.getMapping().getMappedJavaClass() != null) {
javaClass = edmProperty.getMapping().getMappedJavaClass();
} else {
javaClass = edmPrimitiveType.getDefaultType();
}
edmPrimitiveType.getDefaultType();
return javaClass;
}
/**
* Check if JsonNode is a value node (<code>jsonNode.isValueNode()</code>) and if not throw
* an DeserializerException.

View File

@ -0,0 +1,70 @@
/*
* 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.server.core.edm.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.Date;
import org.apache.olingo.commons.api.edm.EdmParameter;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.server.api.edm.provider.Mapping;
import org.apache.olingo.server.api.edm.provider.Parameter;
import org.apache.olingo.server.api.edm.provider.Property;
import org.junit.Test;
public class EdmMappingTest {
@Test
public void initialMappingMustBeNull() {
Property property = new Property().setType(EdmPrimitiveTypeKind.DateTime.getFullQualifiedName());
EdmProperty edmProperty = new EdmPropertyImpl(null, new FullQualifiedName("namespace.name"), property);
assertNull(edmProperty.getMapping());
Parameter parameter = new Parameter().setType(EdmPrimitiveTypeKind.DateTime.getFullQualifiedName());
EdmParameter edmParameter = new EdmParameterImpl(null, parameter);
assertNull(edmParameter.getMapping());
}
@Test
public void getDataClassForPrimTypeViaMapping() {
Mapping mapping = new Mapping().setMappedJavaClass(Date.class);
Property property = new Property()
.setType(EdmPrimitiveTypeKind.DateTime.getFullQualifiedName())
.setMapping(mapping);
EdmProperty edmProperty = new EdmPropertyImpl(null, new FullQualifiedName("namespace.name"), property);
assertNotNull(edmProperty.getMapping());
assertEquals(Date.class, edmProperty.getMapping().getMappedJavaClass());
Parameter parameter = new Parameter()
.setType(EdmPrimitiveTypeKind.DateTime.getFullQualifiedName())
.setMapping(mapping);
EdmParameter edmParameter = new EdmParameterImpl(null, parameter);
assertNotNull(edmParameter.getMapping());
assertEquals(Date.class, edmParameter.getMapping().getMappedJavaClass());
}
}

View File

@ -24,10 +24,15 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.olingo.commons.api.data.Entity;
@ -35,11 +40,19 @@ import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.domain.ODataLinkType;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.apache.olingo.server.api.edm.provider.Mapping;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.junit.Test;
public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest {
@ -553,6 +566,7 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
assertNull(entity.getProperty("PropertyComp").getValue());
}
@SuppressWarnings("unchecked")
@Test
public void validJsonValueForComplexCollectionNullValue() throws Exception {
final String entityString = "{"
@ -603,6 +617,50 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
assertNull(propertyCompMixedEnumDef.asComplex().get(0).getValue());
}
@SuppressWarnings("unused")
@Test
public void mappingTest() throws Exception {
Edm localEdm =
OData.newInstance().createServiceMetadata(new EdmTechProvider(), Collections.<EdmxReference> emptyList())
.getEdm();
EdmEntityType entityType = mock(EdmEntityType.class);
when(entityType.getFullQualifiedName()).thenReturn(new FullQualifiedName("napespace", "name"));
List<String> propertyNames = new ArrayList<String>();
propertyNames.add("PropertyDate");
propertyNames.add("PropertyDateTimeOffset");
when(entityType.getPropertyNames()).thenReturn(propertyNames);
Mapping mapping = new Mapping().setMappedJavaClass(Date.class);
EdmProperty propertyDate = mock(EdmProperty.class);
when(propertyDate.getName()).thenReturn("PropertyDate");
when(propertyDate.getMapping()).thenReturn(mapping);
when(propertyDate.getType()).thenReturn(new EdmDate());
when(entityType.getProperty("PropertyDate")).thenReturn(propertyDate);
EdmProperty propertyDateTimeOffset = mock(EdmProperty.class);
when(propertyDateTimeOffset.getName()).thenReturn("PropertyDateTimeOffset");
when(propertyDateTimeOffset.getMapping()).thenReturn(mapping);
when(propertyDateTimeOffset.getType()).thenReturn(new EdmDateTimeOffset());
when(entityType.getProperty("PropertyDateTimeOffset")).thenReturn(propertyDateTimeOffset);
String entityString =
"{\"PropertyDate\":\"2012-12-03\","
+ "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"}";
InputStream stream = new ByteArrayInputStream(entityString.getBytes());
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
Entity entity =
deserializer.entity(stream, entityType);
assertNotNull(entity);
List<Property> properties = entity.getProperties();
assertNotNull(properties);
assertEquals(2, properties.size());
assertNotNull(entity.getProperty("PropertyDate").getValue());
assertEquals(Date.class, entity.getProperty("PropertyDate").getValue().getClass());
assertNotNull(entity.getProperty("PropertyDateTimeOffset").getValue());
assertEquals(Date.class, entity.getProperty("PropertyDateTimeOffset").getValue().getClass());
}
// ---------------------------------- Negative Tests -----------------------------------------------------------