[OLINGO-795] server support for Enums with implicit values

Change-Id: I1d96eecb108479a654f10426204d4d1e1383bb09

Signed-off-by: Christian Holzer <c.holzer@sap.com>
This commit is contained in:
Klaus Straubinger 2015-10-15 09:58:09 +02:00 committed by Christian Holzer
parent 5d364dfa27
commit 587f904338
4 changed files with 77 additions and 89 deletions

View File

@ -92,6 +92,10 @@ public class EdmEnumTypeImpl extends EdmTypeImpl implements EdmEnumType {
return Collections.unmodifiableList(memberNames);
}
/**
* Creates the map from member names to member objects,
* preserving the order for the case of implicit value assignments.
*/
private void createEdmMembers() {
final Map<String, EdmMember> membersMapLocal = new LinkedHashMap<String, EdmMember>();
final List<String> memberNamesLocal = new ArrayList<String>();
@ -132,9 +136,11 @@ public class EdmEnumTypeImpl extends EdmTypeImpl implements EdmEnumType {
Long result = null;
for (final String memberValue : value.split(",", isFlags() ? -1 : 1)) {
Long memberValueLong = null;
long count = 0;
for (final EdmMember member : getMembers()) {
if (member.getName().equals(memberValue) || member.getValue().equals(memberValue)) {
memberValueLong = Long.decode(member.getValue());
count++;
if (memberValue.equals(member.getName()) || memberValue.equals(member.getValue())) {
memberValueLong = member.getValue() == null ? count - 1 : Long.decode(member.getValue());
}
}
if (memberValueLong == null) {
@ -172,8 +178,9 @@ public class EdmEnumTypeImpl extends EdmTypeImpl implements EdmEnumType {
StringBuilder result = new StringBuilder();
final boolean flags = isFlags();
long memberValue = -1;
for (final EdmMember member : getMembers()) {
final long memberValue = Long.parseLong(member.getValue());
memberValue = member.getValue() == null ? memberValue + 1 : Long.parseLong(member.getValue());
if (flags) {
if ((memberValue & remaining) == memberValue) {
if (result.length() > 0) {

View File

@ -71,31 +71,28 @@ public class EdmEnumTest {
new CsdlEnumType().setName("name").setMembers(memberList).setFlags(false)
.setUnderlyingType(EdmPrimitiveTypeKind.SByte.getFullQualifiedName()));
int16EnumType = new EdmEnumTypeImpl(null,
new FullQualifiedName("testNamespace", "testName"),
new CsdlEnumType().setName("MyEnum")
.setFlags(false)
.setUnderlyingType(EdmPrimitiveTypeKind.Int16.getFullQualifiedName())
.setMembers(Arrays.asList(
new CsdlEnumMember().setName("A").setValue("0"),
new CsdlEnumMember().setName("B").setValue("1"),
new CsdlEnumMember().setName("C").setValue("2"))));
final FullQualifiedName testName = new FullQualifiedName("testNamespace", "testName");
int32EnumType = new EdmEnumTypeImpl(null,
new FullQualifiedName("testNamespace", "testName"),
int16EnumType = new EdmEnumTypeImpl(null, testName,
new CsdlEnumType().setName("MyEnum")
.setUnderlyingType(EdmPrimitiveTypeKind.Int16.getFullQualifiedName())
.setMembers(Arrays.asList( // implicit values according to specification: 0, 1, 2
new CsdlEnumMember().setName("A"),
new CsdlEnumMember().setName("B"),
new CsdlEnumMember().setName("C"))));
int32EnumType = new EdmEnumTypeImpl(null, testName,
new CsdlEnumType().setName("MyEnum")
.setFlags(false)
.setUnderlyingType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName())
.setMembers(Arrays.asList(
new CsdlEnumMember().setName("A").setValue("0"),
new CsdlEnumMember().setName("B").setValue("1"),
new CsdlEnumMember().setName("C").setValue("2"))));
new CsdlEnumMember().setName("C").setValue("65536"))));
int32FlagType = new EdmEnumTypeImpl(null,
new FullQualifiedName("testNamespace", "testName"),
int32FlagType = new EdmEnumTypeImpl(null, testName,
new CsdlEnumType().setName("MyEnum")
.setFlags(true)
.setUnderlyingType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName())
.setMembers(Arrays.asList(
new CsdlEnumMember().setName("A").setValue("2"),
new CsdlEnumMember().setName("B").setValue("4"),
@ -127,16 +124,13 @@ public class EdmEnumTest {
@Test
public void defaultType() throws Exception {
assertEquals(Byte.class, instance.getDefaultType());
EdmEnumType instance = new EdmEnumTypeImpl(null,
new FullQualifiedName("testNamespace", "testName"),
new CsdlEnumType().setName("MyEnum"));
assertEquals(Integer.class, instance.getUnderlyingType().getDefaultType());
assertEquals(Integer.class, int32FlagType.getUnderlyingType().getDefaultType());
}
@Test
public void members() throws Exception {
assertArrayEquals(new String[] { "first", "second" }, instance.getMemberNames().toArray());
assertEquals("64", instance.getMember("second").getValue());
assertEquals("64", otherInstance.getMember("second").getValue());
assertNull(instance.getMember("notExisting"));
}
@ -145,6 +139,13 @@ public class EdmEnumTest {
assertEquals(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte), instance.getUnderlyingType());
}
@Test
public void isFlags() throws Exception {
assertTrue(instance.isFlags());
assertFalse(nonFlagsInstance.isFlags());
assertFalse(int16EnumType.isFlags());
}
@Test
public void validate() throws Exception {
assertTrue(instance.validate(null, null, null, null, null, null));
@ -193,7 +194,7 @@ public class EdmEnumTest {
assertEquals("A", int32EnumType.valueToString(0, false, 0, 0, 0, false));
assertEquals("B", int32EnumType.valueToString(1, false, 0, 0, 0, false));
assertEquals("C", int32EnumType.valueToString(2, false, 0, 0, 0, false));
assertEquals("C", int32EnumType.valueToString(65536, false, 0, 0, 0, false));
assertEquals("A", int16EnumType.valueToString(0, false, 0, 0, 0, false));
assertEquals("B", int16EnumType.valueToString(1, false, 0, 0, 0, false));
@ -228,11 +229,17 @@ public class EdmEnumTest {
assertEquals(Integer.valueOf(0), int32EnumType.valueOfString("A", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(1), int32EnumType.valueOfString("B", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(2), int32EnumType.valueOfString("C", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(65536), int32EnumType.valueOfString("C", null, null, null, null, null,
Integer.class));
assertEquals(Integer.valueOf(0), int16EnumType.valueOfString("A", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(1), int16EnumType.valueOfString("B", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(2), int16EnumType.valueOfString("C", null, null, null, null, null, Integer.class));
expectErrorInValueOfString(int32EnumType, "65536", null, Short.class, "converted");
assertEquals(Short.valueOf((short) 0), int16EnumType.valueOfString("A", null, null, null, null, null,
Short.class));
assertEquals(Short.valueOf((short) 1), int16EnumType.valueOfString("B", null, null, null, null, null,
Short.class));
assertEquals(Short.valueOf((short) 2), int16EnumType.valueOfString("C", null, null, null, null, null,
Short.class));
assertEquals(Integer.valueOf(2), int32FlagType.valueOfString("A", null, null, null, null, null, Integer.class));
assertEquals(Integer.valueOf(4), int32FlagType.valueOfString("B", null, null, null, null, null, Integer.class));
@ -245,47 +252,31 @@ public class EdmEnumTest {
Integer.class));
}
private void expectErrorInValueToString(final EdmEnumType instance,
final Object value, final Boolean isNullable, final Integer maxLength,
final Integer precision, final Integer scale, final Boolean isUnicode,
final String message) {
try {
instance.valueToString(value, isNullable, maxLength, precision, scale, isUnicode);
fail("Expected exception not thrown");
} catch (final EdmPrimitiveTypeException e) {
assertNotNull(e.getLocalizedMessage());
assertThat(e.getLocalizedMessage(), containsString(message));
}
}
private void expectErrorInUnderlyingType(final EdmPrimitiveTypeKind underlyingType, final String message) {
private void expectErrorInUnderlyingType(final EdmPrimitiveTypeKind underlyingType) {
try {
new EdmEnumTypeImpl(null,
new FullQualifiedName("testNamespace", "testName"),
new CsdlEnumType()
.setName("MyEnum")
.setFlags(false)
.setUnderlyingType(underlyingType.getFullQualifiedName())
.setMembers(Arrays.asList(
new CsdlEnumMember().setName("A").setValue("0"))));
.setUnderlyingType(underlyingType.getFullQualifiedName()));
fail("Expected exception not thrown");
} catch (final EdmException e) {
assertNotNull(e.getLocalizedMessage());
assertThat(e.getLocalizedMessage(), containsString(message));
assertThat(e.getLocalizedMessage(), containsString("underlying type"));
}
}
@Test
public void unsupportedUnderlyingType() throws Exception {
// Test some random unsupported types
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.Date, "");
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.Geography, "");
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.Guid, "");
// Test some random unsupported types.
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.Date);
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.GeographyPoint);
expectErrorInUnderlyingType(EdmPrimitiveTypeKind.Guid);
}
@Test
public void outOfRangeValueToString() throws Exception {
expectErrorInValueToString(int16EnumType, Integer.MAX_VALUE, null, null, null, null, null, "");
expectContentErrorInValueToString(int16EnumType, Integer.MAX_VALUE);
}
protected void expectErrorInFromUriLiteral(final EdmPrimitiveType instance, final String value) {
@ -298,12 +289,10 @@ public class EdmEnumTest {
}
}
private void expectErrorInValueToString(final EdmPrimitiveType instance,
final Object value, final Boolean isNullable, final Integer maxLength,
final Integer precision, final Integer scale, final Boolean isUnicode,
final String message) {
private void expectErrorInValueToString(final EdmPrimitiveType instance, final Object value,
final Boolean isNullable, final String message) {
try {
instance.valueToString(value, isNullable, maxLength, precision, scale, isUnicode);
instance.valueToString(value, isNullable, null, null, null, null);
fail("Expected exception not thrown");
} catch (final EdmPrimitiveTypeException e) {
assertNotNull(e.getLocalizedMessage());
@ -312,24 +301,21 @@ public class EdmEnumTest {
}
protected void expectNullErrorInValueToString(final EdmPrimitiveType instance) {
expectErrorInValueToString(instance, null, false, null, null, null, null, "The value NULL is not allowed.");
expectErrorInValueToString(instance, null, false, "The value NULL is not allowed.");
}
protected void expectTypeErrorInValueToString(final EdmPrimitiveType instance, final Object value) {
expectErrorInValueToString(instance, value, null, null, null, null, null, "value type");
expectErrorInValueToString(instance, value, null, "value type");
}
protected void expectContentErrorInValueToString(final EdmPrimitiveType instance, final Object value) {
expectErrorInValueToString(instance, value, null, null, null, null, null, "' is not valid.");
expectErrorInValueToString(instance, value, null, "' is not valid.");
}
private void expectErrorInValueOfString(final EdmPrimitiveType instance,
final String value, final Boolean isNullable, final Integer maxLength, final Integer precision,
final Integer scale, final Boolean isUnicode, final Class<?> returnType,
final String message) {
private void expectErrorInValueOfString(final EdmPrimitiveType instance, final String value,
final Boolean isNullable, final Class<?> returnType, final String message) {
try {
instance.valueOfString(value, isNullable, maxLength, precision, scale, isUnicode, returnType);
instance.valueOfString(value, isNullable, null, null, null, null, returnType);
fail("Expected exception not thrown");
} catch (final EdmPrimitiveTypeException e) {
assertNotNull(e.getLocalizedMessage());
@ -338,17 +324,16 @@ public class EdmEnumTest {
}
protected void expectTypeErrorInValueOfString(final EdmPrimitiveType instance, final String value) {
expectErrorInValueOfString(instance, value, null, null, null, null, null, Class.class,
expectErrorInValueOfString(instance, value, null, Class.class,
"The value type class java.lang.Class is not supported.");
}
protected void expectContentErrorInValueOfString(final EdmPrimitiveType instance, final String value) {
expectErrorInValueOfString(instance, value, null, null, null, null, null, instance.getDefaultType(),
"illegal content");
expectErrorInValueOfString(instance, value, null, instance.getDefaultType(), "illegal content");
}
protected void expectNullErrorInValueOfString(final EdmPrimitiveType instance) {
expectErrorInValueOfString(instance, null, false, null, null, null, null, instance.getDefaultType(),
expectErrorInValueOfString(instance, null, false, instance.getDefaultType(),
"The literal 'null' is not allowed.");
}
}

View File

@ -54,16 +54,13 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.core.edm.EdmTypeInfo;
import org.apache.olingo.commons.core.edm.primitivetype.AbstractGeospatialType;
import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
import org.apache.olingo.server.api.deserializer.DeserializerResult;
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
import org.apache.olingo.server.core.deserializer.DeserializerResultImpl;
import com.fasterxml.aalto.stax.InputFactoryImpl;
@ -152,9 +149,7 @@ public class ODataXmlDeserializer implements ODataDeserializer {
final XMLEvent event = reader.nextEvent();
if (event.isStartElement()) {
if (edmType instanceof SingletonPrimitiveType
|| edmType.getKind() == EdmTypeKind.ENUM
|| edmType.getKind() == EdmTypeKind.DEFINITION) {
if (edmType instanceof EdmPrimitiveType) {
values.add(primitive(reader, event.asStartElement(), type, isNullable,
maxLength, precision, scale, isUnicode));
} else if (edmType instanceof EdmComplexType) {
@ -191,14 +186,14 @@ public class ODataXmlDeserializer implements ODataDeserializer {
}
private ValueType getValueType(EdmType edmType, boolean isCollection) {
if (edmType instanceof SingletonPrimitiveType) {
return isCollection? ValueType.COLLECTION_PRIMITIVE:ValueType.PRIMITIVE;
if (edmType instanceof EdmPrimitiveType) {
if (edmType instanceof EdmEnumType) {
return isCollection ? ValueType.COLLECTION_ENUM : ValueType.ENUM;
} else {
return isCollection ? ValueType.COLLECTION_PRIMITIVE : ValueType.PRIMITIVE;
}
} else if (edmType instanceof EdmComplexType) {
return isCollection? ValueType.COLLECTION_COMPLEX:ValueType.COMPLEX;
} else if (edmType instanceof EdmEnumType) {
return isCollection?ValueType.COLLECTION_ENUM:ValueType.ENUM;
} else if (edmType instanceof EdmTypeDefinition) {
return isCollection?ValueType.COLLECTION_PRIMITIVE:ValueType.PRIMITIVE;
return isCollection ? ValueType.COLLECTION_COMPLEX : ValueType.COMPLEX;
} else {
return ValueType.PRIMITIVE;
}
@ -227,9 +222,7 @@ public class ODataXmlDeserializer implements ODataDeserializer {
valuable.setType(isCollection ? ("Collection(" + typeName + ")") : typeName);
if (isCollection) {
collection(valuable, reader, start, edmType, isNullable, maxLength, precision, scale, isUnicode);
} else if (edmType instanceof SingletonPrimitiveType
|| edmType.getKind() == EdmTypeKind.ENUM
|| edmType.getKind() == EdmTypeKind.DEFINITION) {
} else if (edmType instanceof EdmPrimitiveType) {
valuable.setValue(getValueType(edmType, false),
primitive(reader, start, edmType, isNullable, maxLength, precision, scale, isUnicode));
} else if (edmType instanceof EdmComplexType) {

View File

@ -596,13 +596,16 @@ public class MetadataDocumentXmlSerializer {
for (EdmEnumType enumType : enumTypes) {
writer.writeStartElement(XML_ENUM_TYPE);
writer.writeAttribute(XML_NAME, enumType.getName());
writer.writeAttribute(XML_IS_FLAGS, "" + enumType.isFlags());
writer.writeAttribute(XML_IS_FLAGS, Boolean.toString(enumType.isFlags()));
writer.writeAttribute(XML_UNDERLYING_TYPE, getFullQualifiedName(enumType.getUnderlyingType(), false));
for (String memberName : enumType.getMemberNames()) {
writer.writeEmptyElement(XML_MEMBER);
writer.writeAttribute(XML_NAME, memberName);
writer.writeAttribute(XML_VALUE, enumType.getMember(memberName).getValue());
final String value = enumType.getMember(memberName).getValue();
if (value != null) {
writer.writeAttribute(XML_VALUE, value);
}
}
writer.writeEndElement();