diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java
new file mode 100644
index 0000000000..7d880655d9
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java
@@ -0,0 +1,287 @@
+package org.restlet.ext.odata;
+
+import static org.restlet.ext.odata.internal.edm.TypeUtils.dateTimeFormats;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.decimalFormat;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.doubleFormat;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.singleFormat;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.timeFormat;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmBinary;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmBoolean;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmByte;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDateTime;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDecimal;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDouble;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt16;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt32;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt64;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmSingle;
+import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmTime;
+
+import java.util.Date;
+
+import org.restlet.Context;
+import org.restlet.engine.util.Base64;
+import org.restlet.engine.util.DateUtils;
+import org.restlet.ext.odata.internal.edm.Type;
+
+/**
+ * Util class used to convert values to and from Edm types.
+ * Can be overriden to extends basic behaviour.
+ */
+public class EdmConverter {
+
+ /**
+ * Converts the String representation of the target WCF type to its
+ * corresponding value.
+ *
+ * @param value
+ * The value to convert.
+ * @param adoNetType
+ * The target WCF type.
+ * @return The converted value.
+ */
+ public Object fromEdm(String value, String adoNetType) {
+ if (value == null) {
+ return null;
+ }
+
+ Object result = null;
+ try {
+ if (adoNetType.endsWith("Binary")) {
+ result = Base64.decode(value);
+ } else if (adoNetType.endsWith("Boolean")) {
+ result = Boolean.valueOf(value);
+ } else if (adoNetType.endsWith("DateTime")) {
+ result = DateUtils.parse(value, dateTimeFormats);
+ } else if (adoNetType.endsWith("DateTimeOffset")) {
+ result = DateUtils.parse(value, dateTimeFormats);
+ } else if (adoNetType.endsWith("Time")) {
+ result = timeFormat.parseObject(value);
+ } else if (adoNetType.endsWith("Decimal")) {
+ result = decimalFormat.parseObject(value);
+ } else if (adoNetType.endsWith("Single")) {
+ result = singleFormat.parseObject(value);
+ } else if (adoNetType.endsWith("Double")) {
+ result = doubleFormat.parseObject(value);
+ } else if (adoNetType.endsWith("Guid")) {
+ result = value;
+ } else if (adoNetType.endsWith("Int16")) {
+ result = Short.valueOf(value);
+ } else if (adoNetType.endsWith("Int32")) {
+ result = Integer.valueOf(value);
+ } else if (adoNetType.endsWith("Int64")) {
+ result = Long.valueOf(value);
+ } else if (adoNetType.endsWith("Byte")) {
+ result = Byte.valueOf(value);
+ } else if (adoNetType.endsWith("String")) {
+ result = value;
+ }
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot convert " + value + " from this EDM type "
+ + adoNetType);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the literal form of the given value.
+ *
+ * @param value
+ * The value to convert.
+ * @param adoNetType
+ * The type of the value.
+ * @return The literal form of the given value.
+ * @see Abstract Type
+ * System
+ */
+ public String getLiteralForm(String value, String adoNetType) {
+ if (value == null) {
+ return null;
+ }
+
+ String result = null;
+ try {
+ if (adoNetType.endsWith("Binary")) {
+ result = "'" + value + "'";
+ } else if (adoNetType.endsWith("DateTime")) {
+ result = "datetime'" + value + "'";
+ } else if (adoNetType.endsWith("DateTimeOffset")) {
+ result = "datetimeoffset'" + value + "'";
+ } else if (adoNetType.endsWith("Time")) {
+ result = "time'" + value + "'";
+ } else if (adoNetType.endsWith("Guid")) {
+ result = "guid'" + value + "'";
+ } else if (adoNetType.endsWith("String")) {
+ result = "'" + value + "'";
+ }
+ } catch (Exception e) {
+ Context.getCurrentLogger().warning(
+ "Cannot convert " + value + " from this EDM type "
+ + adoNetType);
+ }
+
+ return result;
+ }
+
+ /**
+ * Converts a value to the String representation of the target WCF type.
+ *
+ * @param value
+ * The value to convert.
+ * @param type
+ * The target WCF type.
+ * @return The converted value.
+ */
+ public String toEdm(Object value, Type type) {
+ String adoNetType = type.getName();
+ if (value == null || adoNetType == null) {
+ return null;
+ }
+
+ String result = null;
+ if (adoNetType.endsWith("Binary")) {
+ if ((byte[].class).isAssignableFrom(value.getClass())) {
+ result = toEdmBinary((byte[]) value);
+ }
+ } else if (adoNetType.endsWith("Boolean")) {
+ if ((Boolean.class).isAssignableFrom(value.getClass())) {
+ result = toEdmBoolean((Boolean) value);
+ }
+ } else if (adoNetType.endsWith("DateTime")) {
+ if ((Date.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDateTime((Date) value);
+ }
+ } else if (adoNetType.endsWith("DateTimeOffset")) {
+ if ((Date.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDateTime((Date) value);
+ }
+ } else if (adoNetType.endsWith("Time")) {
+ if ((Long.class).isAssignableFrom(value.getClass())) {
+ result = toEdmTime((Long) value);
+ }
+ } else if (adoNetType.endsWith("Decimal")) {
+ if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDecimal((Double) value);
+ }
+ } else if (adoNetType.endsWith("Single")) {
+ if ((Float.class).isAssignableFrom(value.getClass())) {
+ result = toEdmSingle((Float) value);
+ } else if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmSingle((Double) value);
+ }
+ } else if (adoNetType.endsWith("Double")) {
+ if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDouble((Double) value);
+ }
+ } else if (adoNetType.endsWith("Guid")) {
+ result = value.toString();
+ } else if (adoNetType.endsWith("Int16")) {
+ if ((Short.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt16((Short) value);
+ }
+ } else if (adoNetType.endsWith("Int32")) {
+ if ((Integer.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt32((Integer) value);
+ }
+ } else if (adoNetType.endsWith("Int64")) {
+ if ((Long.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt64((Long) value);
+ }
+ } else if (adoNetType.endsWith("Byte")) {
+ if ((Byte.class).isAssignableFrom(value.getClass())) {
+ result = toEdmByte((Byte) value);
+ }
+ } else if (adoNetType.endsWith("String")) {
+ result = value.toString();
+ }
+
+ if (result == null) {
+ result = value.toString();
+ }
+
+ return result;
+ }
+
+ /**
+ * Converts a value to the String representation of the target WCF type when
+ * used a key in the URIs.
+ *
+ * @param value
+ * The value to convert.
+ * @param type
+ * The target WCF type.
+ * @return The converted value.
+ */
+ public String toEdmKey(Object value, Type type) {
+ String adoNetType = type.getName();
+ if (value == null || adoNetType == null) {
+ return null;
+ }
+
+ String result = null;
+ if (adoNetType.endsWith("Binary")) {
+ if ((byte[].class).isAssignableFrom(value.getClass())) {
+ result = toEdmBinary((byte[]) value);
+ }
+ } else if (adoNetType.endsWith("Boolean")) {
+ if ((Boolean.class).isAssignableFrom(value.getClass())) {
+ result = toEdmBoolean((Boolean) value);
+ }
+ } else if (adoNetType.endsWith("DateTime")) {
+ if ((Date.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDateTime((Date) value);
+ }
+ } else if (adoNetType.endsWith("DateTimeOffset")) {
+ if ((Date.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDateTime((Date) value);
+ }
+ } else if (adoNetType.endsWith("Time")) {
+ if ((Long.class).isAssignableFrom(value.getClass())) {
+ result = toEdmTime((Long) value);
+ }
+ } else if (adoNetType.endsWith("Decimal")) {
+ if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDecimal((Double) value);
+ }
+ } else if (adoNetType.endsWith("Single")) {
+ if ((Float.class).isAssignableFrom(value.getClass())) {
+ result = toEdmSingle((Float) value);
+ } else if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmSingle((Double) value);
+ }
+ } else if (adoNetType.endsWith("Double")) {
+ if ((Double.class).isAssignableFrom(value.getClass())) {
+ result = toEdmDouble((Double) value);
+ }
+ } else if (adoNetType.endsWith("Guid")) {
+ result = value.toString();
+ } else if (adoNetType.endsWith("Int16")) {
+ if ((Short.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt16((Short) value);
+ }
+ } else if (adoNetType.endsWith("Int32")) {
+ if ((Integer.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt32((Integer) value);
+ }
+ } else if (adoNetType.endsWith("Int64")) {
+ if ((Long.class).isAssignableFrom(value.getClass())) {
+ result = toEdmInt64((Long) value);
+ }
+ } else if (adoNetType.endsWith("Byte")) {
+ if ((Byte.class).isAssignableFrom(value.getClass())) {
+ result = toEdmByte((Byte) value);
+ }
+ } else if (adoNetType.endsWith("String")) {
+ result = "'" + value.toString() + "'";
+ }
+
+ if (result == null) {
+ result = value.toString();
+ }
+
+ return result;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
index d4e78cf36a..b31a4b9b74 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java
@@ -31,6 +31,7 @@
import java.util.HashMap;
import java.util.Map;
+import org.restlet.data.ChallengeResponse;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Reference;
@@ -48,6 +49,8 @@
import freemarker.template.Configuration;
+import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty;
+
/**
* Code generator for accessing OData services. The generator use metadata
* exposed by an online service to generate client-side artifacts facilitating
@@ -61,8 +64,7 @@ public class Generator {
* Takes two (or three) parameters:
*
* - The URI of the OData service
- * - The output directory (optional, used the current directory by
- * default)
+ * - The output directory (optional, used the current directory by default)
* - The name of the generated service class name (optional)
*
*
@@ -164,6 +166,9 @@ public static void main(String[] args) {
/** The name of the service class (in case there is only one in the schema). */
private String serviceClassName;
+ /** The credentials used to request the OData service. */
+ private ChallengeResponse serviceCredentials;
+
/** The URI of the target data service. */
private Reference serviceRef;
@@ -231,6 +236,7 @@ public Generator(String serviceUri, String serviceClassName) {
*/
public void generate(File outputDir) throws Exception {
Service service = new Service(serviceRef);
+ service.setCredentials(serviceCredentials);
Metadata metadata = (Metadata) service.getMetadata();
if (metadata == null) {
throw new Exception("Can't get the metadata for this service: "
@@ -253,13 +259,9 @@ public void generate(File outputDir) throws Exception {
.getText());
for (Schema schema : metadata.getSchemas()) {
- if ((schema.getEntityTypes() != null && !schema.getEntityTypes()
- .isEmpty())
- || (schema.getComplexTypes() != null && !schema
- .getComplexTypes().isEmpty())) {
+ if (!isNullOrEmpty(schema.getEntityTypes()) || !isNullOrEmpty(schema.getComplexTypes())) {
String packageName = TypeUtils.getPackageName(schema);
- File packageDir = new File(outputDir, packageName.replace(".",
- System.getProperty("file.separator")));
+ File packageDir = new File(outputDir, packageName.replace(".", System.getProperty("file.separator")));
packageDir.mkdirs();
// For each entity type
@@ -272,13 +274,11 @@ public void generate(File outputDir) throws Exception {
dataModel.put("className", className);
dataModel.put("packageName", packageName);
- TemplateRepresentation templateRepresentation = new TemplateRepresentation(
- entityTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
+ TemplateRepresentation templateRepresentation = new TemplateRepresentation(entityTmpl, fmc, dataModel, MediaType.TEXT_PLAIN);
templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
// Write the template representation as a Java class
- OutputStream fos = new FileOutputStream(new File(
- packageDir, type.getClassName() + ".java"));
+ OutputStream fos = new FileOutputStream(new File(packageDir, type.getClassName() + ".java"));
templateRepresentation.write(fos);
fos.flush();
}
@@ -304,8 +304,7 @@ public void generate(File outputDir) throws Exception {
}
}
}
- if (metadata.getContainers() != null
- && !metadata.getContainers().isEmpty()) {
+ if (!isNullOrEmpty(metadata.getContainers())) {
for (EntityContainer entityContainer : metadata.getContainers()) {
Schema schema = entityContainer.getSchema();
// Generate Service subclass
@@ -345,8 +344,7 @@ public void generate(File outputDir) throws Exception {
templateRepresentation.setCharacterSet(CharacterSet.UTF_8);
// Write the template representation as a Java class
- OutputStream fos = new FileOutputStream(new File(outputDir,
- className + ".java"));
+ OutputStream fos = new FileOutputStream(new File(outputDir, className + ".java"));
templateRepresentation.write(fos);
fos.flush();
}
@@ -363,4 +361,14 @@ public void generate(File outputDir) throws Exception {
public void generate(String outputDir) throws Exception {
generate(new File(outputDir));
}
+
+ /**
+ * Set the credentials used to request the OData service.
+ *
+ * @param serviceCredentials
+ * The credentials.
+ */
+ public void setServiceCredentials(ChallengeResponse serviceCredentials) {
+ this.serviceCredentials = serviceCredentials;
+ }
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java
new file mode 100644
index 0000000000..1f86de8d2b
--- /dev/null
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java
@@ -0,0 +1,93 @@
+package org.restlet.ext.odata;
+
+import java.util.Date;
+
+/**
+ * Handles the conversion from Edm type to Java class.
+ */
+public class JavaTypeHandler {
+
+ /**
+ * Returns the corresponding Java class or scalar type.
+ *
+ * @param edmTypeName
+ * The type name.
+ * @return The corresponding Java class or scalar type.
+ */
+ public Class> toJavaClass(String edmTypeName) {
+ Class> result = Object.class;
+ if (edmTypeName.endsWith("Binary")) {
+ result = byte[].class;
+ } else if (edmTypeName.endsWith("Boolean")) {
+ result = Boolean.class;
+ } else if (edmTypeName.endsWith("DateTime")) {
+ result = Date.class;
+ } else if (edmTypeName.endsWith("DateTimeOffset")) {
+ result = Date.class;
+ } else if (edmTypeName.endsWith("Time")) {
+ result = Long.class;
+ } else if (edmTypeName.endsWith("Decimal")) {
+ result = Double.class;
+ } else if (edmTypeName.endsWith("Single")) {
+ result = Double.class;
+ } else if (edmTypeName.endsWith("Double")) {
+ result = Double.class;
+ } else if (edmTypeName.endsWith("Guid")) {
+ result = String.class;
+ } else if (edmTypeName.endsWith("Int16")) {
+ result = Short.class;
+ } else if (edmTypeName.endsWith("Int32")) {
+ result = Integer.class;
+ } else if (edmTypeName.endsWith("Int64")) {
+ result = Long.class;
+ } else if (edmTypeName.endsWith("Byte")) {
+ result = Byte.class;
+ } else if (edmTypeName.endsWith("String")) {
+ result = String.class;
+ }
+
+ return result;
+ }
+ /**
+ * Returns the name of the corresponding Java class or scalar type.
+ *
+ * @param edmTypeName
+ * The type name.
+ * @return The name of the corresponding Java class or scalar type.
+ */
+ public String toJavaTypeName(String edmTypeName) {
+ String result = "Object";
+ if (edmTypeName.endsWith("Binary")) {
+ result = "byte[]";
+ } else if (edmTypeName.endsWith("Boolean")) {
+ result = "boolean";
+ } else if (edmTypeName.endsWith("DateTime")) {
+ result = "Date";
+ } else if (edmTypeName.endsWith("DateTimeOffset")) {
+ result = "Date";
+ } else if (edmTypeName.endsWith("Time")) {
+ result = "long";
+ } else if (edmTypeName.endsWith("Decimal")) {
+ result = "double";
+ } else if (edmTypeName.endsWith("Single")) {
+ result = "double";
+ } else if (edmTypeName.endsWith("Double")) {
+ result = "double";
+ } else if (edmTypeName.endsWith("Guid")) {
+ result = "String";
+ } else if (edmTypeName.endsWith("Int16")) {
+ result = "short";
+ } else if (edmTypeName.endsWith("Int32")) {
+ result = "int";
+ } else if (edmTypeName.endsWith("Int64")) {
+ result = "long";
+ } else if (edmTypeName.endsWith("Byte")) {
+ result = "byte";
+ } else if (edmTypeName.endsWith("String")) {
+ result = "String";
+ }
+
+ return result;
+ }
+
+}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
index 504f5972de..9c20762a9c 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java
@@ -112,6 +112,8 @@ public class Service {
/** The credentials used to authenticate requests. */
private ChallengeResponse credentials;
+ private boolean hasServiceUriBeenChecked;
+
/** The latest request sent to the service. */
private Request latestRequest;
@@ -146,36 +148,7 @@ public class Service {
* The reference to the WCF service.
*/
public Service(Reference serviceRef) {
- try {
- // Test the given service URI which may be actually redirected.
- ClientResource cr = new ClientResource(serviceRef);
- if (cr.getNext() == null) {
- // The context does not provide a client connector.
- // Let instantiate our own.
- Protocol rProtocol = cr.getProtocol();
- Reference rReference = cr.getReference();
- Protocol protocol = (rProtocol != null) ? rProtocol
- : (rReference != null) ? rReference.getSchemeProtocol()
- : null;
-
- if (protocol != null) {
- this.clientConnector = new Client(protocol);
- // Set the next handler for reuse
- cr.setNext(this.clientConnector);
- }
- }
-
- cr.setFollowingRedirects(false);
- cr.get();
-
- if (cr.getStatus().isRedirection()) {
- this.serviceRef = cr.getLocationRef();
- } else {
- this.serviceRef = cr.getReference();
- }
- } catch (Throwable e) {
- this.serviceRef = serviceRef;
- }
+ this.serviceRef = serviceRef;
}
/**
@@ -253,6 +226,35 @@ public void addLink(Object source, String sourceProperty, Object target)
}
}
+ private void checkServiceReference(Reference serviceRef) {
+ try {
+ // Test the given service URI which may be actually redirected.
+ ClientResource cr = createResource(serviceRef);
+ if (cr.getNext() == null) {
+ // The context does not provide a client connector.
+ // Let instantiate our own.
+ Protocol rProtocol = cr.getProtocol();
+ Reference rReference = cr.getReference();
+ Protocol protocol = (rProtocol != null) ? rProtocol
+ : (rReference != null) ? rReference.getSchemeProtocol()
+ : null;
+
+ if (protocol != null) {
+ this.clientConnector = new Client(protocol);
+ // Set the next handler for reuse
+ cr.setNext(this.clientConnector);
+ }
+ }
+
+ cr.setFollowingRedirects(true);
+ cr.get();
+ this.serviceRef = cr.getResponse().getRequest().getResourceRef();
+ } catch (Throwable e) {
+ this.serviceRef = serviceRef;
+ }
+ hasServiceUriBeenChecked = true;
+ }
+
/**
* Creates a query to a specific entity hosted by this service.
*
@@ -288,7 +290,7 @@ public ClientResource createResource(Reference reference) {
resource.setChallengeResponse(getCredentials());
if (getClientVersion() != null || getMaxClientVersion() != null) {
- Series headers = new Series(Header.class);
+ Series headers = resource.getRequest().getHeaders();
if (getClientVersion() != null) {
headers.add("DataServiceVersion", getClientVersion());
@@ -297,8 +299,6 @@ public ClientResource createResource(Reference reference) {
if (getMaxClientVersion() != null) {
headers.add("MaxDataServiceVersion", getMaxClientVersion());
}
-
- resource.setAttribute(HeaderConstants.ATTRIBUTE_HEADERS, headers);
}
return resource;
@@ -533,6 +533,9 @@ public String getServerVersion() {
* @return The reference to the WCF service.
*/
public Reference getServiceRef() {
+ if (!hasServiceUriBeenChecked) {
+ checkServiceReference(serviceRef);
+ }
return serviceRef;
}
@@ -816,9 +819,7 @@ public Reference getValueRef(Object entity) {
* @return The representation returned by the invocation of the service.
* @throws ResourceException
* Thrown when the service call is not successfull.
- * @see Service
- * Operations
+ * @see Service Operations
*/
public Representation invokeComplex(String service,
Series parameters) throws ResourceException {
@@ -847,8 +848,7 @@ public Representation invokeComplex(String service,
.getParameters()) {
resource.getReference().addQueryParameter(
parameter.getName(),
- TypeUtils.getLiteralForm(parameters
- .getFirstValue(parameter.getName()),
+ TypeUtils.getLiteralForm(parameters.getFirstValue(parameter.getName()),
parameter.getType()));
}
}
@@ -879,9 +879,7 @@ public Representation invokeComplex(String service,
* Thrown when the service call is not successfull.
* @throws Exception
* Thrown when the value cannot be parsed.
- * @see Service
- * Operations
+ * @see Service Operations
*/
public String invokeSimple(String service, Series parameters)
throws ResourceException, Exception {
@@ -956,6 +954,26 @@ public void loadProperty(Object entity, String propertyName) {
}
}
+ /**
+ * Allows to specify a new Edm type converter.
+ *
+ * @param edmConverter
+ * The new EdmType converter.
+ */
+ public void registerEdmConverter(EdmConverter edmConverter) {
+ TypeUtils.registerEdmConverter(edmConverter);
+ }
+
+ /**
+ * Allows to specify a new Java type handler.
+ *
+ * @param javaTypeHandler
+ * The new Java type handler.
+ */
+ public static void registerJavaTypeHandler(JavaTypeHandler javaTypeHandler) {
+ TypeUtils.registerJavaTypeHandler(javaTypeHandler);
+ }
+
/**
* Sets the version of the OData protocol extensions defined in every
* request issued by this service.
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
index 0dcd0816ee..84e9086156 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java
@@ -34,6 +34,8 @@
import org.restlet.ext.xml.SaxRepresentation;
import org.restlet.representation.Representation;
+import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty;
+
/**
* Represents the metadata of an OData service.
*
@@ -212,7 +214,7 @@ public EntityType getEntityType(Class> entityClass) {
public String getKeyValue(EntityType type, Object entity) {
StringBuffer result = new StringBuffer();
- if (type.getKeys() != null && !type.getKeys().isEmpty()) {
+ if (!isNullOrEmpty(type.getKeys())) {
if (type.getKeys().size() == 1) {
Property key = type.getKeys().get(0);
String keyName = key.getNormalizedName();
@@ -220,8 +222,7 @@ public String getKeyValue(EntityType type, Object entity) {
+ keyName.substring(0, 1).toUpperCase()
+ keyName.substring(1);
try {
- Method getter = entity.getClass().getDeclaredMethod(
- getterName, (Class[]) null);
+ Method getter = entity.getClass().getDeclaredMethod(getterName, (Class[]) null);
Object value = getter.invoke(entity, (Object[]) null);
String strValue = TypeUtils.toEdmKey(value, key.getType());
if (strValue != null) {
@@ -242,11 +243,9 @@ public String getKeyValue(EntityType type, Object entity) {
+ keyName.substring(0, 1).toUpperCase()
+ keyName.substring(1);
try {
- Method getter = entity.getClass().getDeclaredMethod(
- getterName, (Class[]) null);
+ Method getter = entity.getClass().getDeclaredMethod(getterName, (Class[]) null);
Object value = getter.invoke(entity, (Object[]) null);
- String strValue = TypeUtils.toEdmKey(value,
- key.getType());
+ String strValue = TypeUtils.toEdmKey(value, key.getType());
if (strValue != null) {
result.append(strValue);
} else {
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
index 188f51abc4..67fe446c21 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java
@@ -31,10 +31,13 @@
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import org.restlet.Context;
import org.restlet.engine.util.Base64;
import org.restlet.engine.util.DateUtils;
+import org.restlet.ext.odata.EdmConverter;
+import org.restlet.ext.odata.JavaTypeHandler;
import org.restlet.ext.odata.internal.reflect.ReflectUtils;
/**
@@ -65,6 +68,9 @@ public class TypeUtils {
public static final NumberFormat timeFormat = DecimalFormat
.getIntegerInstance(Locale.US);
+ private static EdmConverter edmConverter = new EdmConverter();
+ private static JavaTypeHandler javaTypeHandler = new JavaTypeHandler();
+
/**
* Converts the String representation of the target WCF type to its
* corresponding value.
@@ -80,44 +86,7 @@ public static Object fromEdm(String value, String adoNetType) {
return null;
}
- Object result = null;
- try {
- if (adoNetType.endsWith("Binary")) {
- result = Base64.decode(value);
- } else if (adoNetType.endsWith("Boolean")) {
- result = Boolean.valueOf(value);
- } else if (adoNetType.endsWith("DateTime")) {
- result = DateUtils.parse(value, dateTimeFormats);
- } else if (adoNetType.endsWith("DateTimeOffset")) {
- result = DateUtils.parse(value, dateTimeFormats);
- } else if (adoNetType.endsWith("Time")) {
- result = timeFormat.parseObject(value);
- } else if (adoNetType.endsWith("Decimal")) {
- result = decimalFormat.parseObject(value);
- } else if (adoNetType.endsWith("Single")) {
- result = singleFormat.parseObject(value);
- } else if (adoNetType.endsWith("Double")) {
- result = doubleFormat.parseObject(value);
- } else if (adoNetType.endsWith("Guid")) {
- result = value;
- } else if (adoNetType.endsWith("Int16")) {
- result = Short.valueOf(value);
- } else if (adoNetType.endsWith("Int32")) {
- result = Integer.valueOf(value);
- } else if (adoNetType.endsWith("Int64")) {
- result = Long.valueOf(value);
- } else if (adoNetType.endsWith("Byte")) {
- result = Byte.valueOf(value);
- } else if (adoNetType.endsWith("String")) {
- result = value;
- }
- } catch (Exception e) {
- Context.getCurrentLogger().warning(
- "Cannot convert " + value + " from this EDM type "
- + adoNetType);
- }
-
- return result;
+ return edmConverter.fromEdm(value, adoNetType);
}
/**
@@ -183,28 +152,7 @@ public static String getLiteralForm(String value, String adoNetType) {
return null;
}
- String result = null;
- try {
- if (adoNetType.endsWith("Binary")) {
- result = "'" + value + "'";
- } else if (adoNetType.endsWith("DateTime")) {
- result = "datetime'" + value + "'";
- } else if (adoNetType.endsWith("DateTimeOffset")) {
- result = "datetimeoffset'" + value + "'";
- } else if (adoNetType.endsWith("Time")) {
- result = "time'" + value + "'";
- } else if (adoNetType.endsWith("Guid")) {
- result = "guid'" + value + "'";
- } else if (adoNetType.endsWith("String")) {
- result = "'" + value + "'";
- }
- } catch (Exception e) {
- Context.getCurrentLogger().warning(
- "Cannot convert " + value + " from this EDM type "
- + adoNetType);
- }
-
- return result;
+ return edmConverter.getLiteralForm(value, adoNetType);
}
/**
@@ -239,7 +187,29 @@ public static String getPackageName(String name) {
}
return builder.toString();
}
+
+ /**
+ * Allows to specify a new Edm type converter.
+ * @param edmConverter
+ * The new Edm type converter.
+ */
+ public static void registerEdmConverter(EdmConverter edmConverter) {
+ Objects.requireNonNull(edmConverter);
+
+ TypeUtils.edmConverter = edmConverter;
+ }
+ /**
+ * Allows to specify a new Java type handler.
+ * @param javaTypeHandler
+ * The new Java type handler.
+ */
+ public static void registerJavaTypeHandler(JavaTypeHandler javaTypeHandler) {
+ Objects.requireNonNull(javaTypeHandler);
+
+ TypeUtils.javaTypeHandler = javaTypeHandler;
+ }
+
/**
* Converts a value to the String representation of the target WCF type.
*
@@ -255,68 +225,7 @@ public static String toEdm(Object value, Type type) {
return null;
}
- String result = null;
- if (adoNetType.endsWith("Binary")) {
- if ((byte[].class).isAssignableFrom(value.getClass())) {
- result = toEdmBinary((byte[]) value);
- }
- } else if (adoNetType.endsWith("Boolean")) {
- if ((Boolean.class).isAssignableFrom(value.getClass())) {
- result = toEdmBoolean((Boolean) value);
- }
- } else if (adoNetType.endsWith("DateTime")) {
- if ((Date.class).isAssignableFrom(value.getClass())) {
- result = toEdmDateTime((Date) value);
- }
- } else if (adoNetType.endsWith("DateTimeOffset")) {
- if ((Date.class).isAssignableFrom(value.getClass())) {
- result = toEdmDateTime((Date) value);
- }
- } else if (adoNetType.endsWith("Time")) {
- if ((Long.class).isAssignableFrom(value.getClass())) {
- result = toEdmTime((Long) value);
- }
- } else if (adoNetType.endsWith("Decimal")) {
- if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmDecimal((Double) value);
- }
- } else if (adoNetType.endsWith("Single")) {
- if ((Float.class).isAssignableFrom(value.getClass())) {
- result = toEdmSingle((Float) value);
- } else if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmSingle((Double) value);
- }
- } else if (adoNetType.endsWith("Double")) {
- if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmDouble((Double) value);
- }
- } else if (adoNetType.endsWith("Guid")) {
- result = value.toString();
- } else if (adoNetType.endsWith("Int16")) {
- if ((Short.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt16((Short) value);
- }
- } else if (adoNetType.endsWith("Int32")) {
- if ((Integer.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt32((Integer) value);
- }
- } else if (adoNetType.endsWith("Int64")) {
- if ((Long.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt64((Long) value);
- }
- } else if (adoNetType.endsWith("Byte")) {
- if ((Byte.class).isAssignableFrom(value.getClass())) {
- result = toEdmByte((Byte) value);
- }
- } else if (adoNetType.endsWith("String")) {
- result = value.toString();
- }
-
- if (result == null) {
- result = value.toString();
- }
-
- return result;
+ return edmConverter.toEdm(value, type);
}
/**
@@ -442,68 +351,7 @@ public static String toEdmKey(Object value, Type type) {
return null;
}
- String result = null;
- if (adoNetType.endsWith("Binary")) {
- if ((byte[].class).isAssignableFrom(value.getClass())) {
- result = toEdmBinary((byte[]) value);
- }
- } else if (adoNetType.endsWith("Boolean")) {
- if ((Boolean.class).isAssignableFrom(value.getClass())) {
- result = toEdmBoolean((Boolean) value);
- }
- } else if (adoNetType.endsWith("DateTime")) {
- if ((Date.class).isAssignableFrom(value.getClass())) {
- result = toEdmDateTime((Date) value);
- }
- } else if (adoNetType.endsWith("DateTimeOffset")) {
- if ((Date.class).isAssignableFrom(value.getClass())) {
- result = toEdmDateTime((Date) value);
- }
- } else if (adoNetType.endsWith("Time")) {
- if ((Long.class).isAssignableFrom(value.getClass())) {
- result = toEdmTime((Long) value);
- }
- } else if (adoNetType.endsWith("Decimal")) {
- if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmDecimal((Double) value);
- }
- } else if (adoNetType.endsWith("Single")) {
- if ((Float.class).isAssignableFrom(value.getClass())) {
- result = toEdmSingle((Float) value);
- } else if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmSingle((Double) value);
- }
- } else if (adoNetType.endsWith("Double")) {
- if ((Double.class).isAssignableFrom(value.getClass())) {
- result = toEdmDouble((Double) value);
- }
- } else if (adoNetType.endsWith("Guid")) {
- result = value.toString();
- } else if (adoNetType.endsWith("Int16")) {
- if ((Short.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt16((Short) value);
- }
- } else if (adoNetType.endsWith("Int32")) {
- if ((Integer.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt32((Integer) value);
- }
- } else if (adoNetType.endsWith("Int64")) {
- if ((Long.class).isAssignableFrom(value.getClass())) {
- result = toEdmInt64((Long) value);
- }
- } else if (adoNetType.endsWith("Byte")) {
- if ((Byte.class).isAssignableFrom(value.getClass())) {
- result = toEdmByte((Byte) value);
- }
- } else if (adoNetType.endsWith("String")) {
- result = "'" + value.toString() + "'";
- }
-
- if (result == null) {
- result = value.toString();
- }
-
- return result;
+ return edmConverter.toEdmKey(value, type);
}
/**
@@ -549,38 +397,7 @@ public static String toEdmTime(long value) {
* @return The corresponding Java class or scalar type.
*/
public static Class> toJavaClass(String edmTypeName) {
- Class> result = Object.class;
- if (edmTypeName.endsWith("Binary")) {
- result = byte[].class;
- } else if (edmTypeName.endsWith("Boolean")) {
- result = Boolean.class;
- } else if (edmTypeName.endsWith("DateTime")) {
- result = Date.class;
- } else if (edmTypeName.endsWith("DateTimeOffset")) {
- result = Date.class;
- } else if (edmTypeName.endsWith("Time")) {
- result = Long.class;
- } else if (edmTypeName.endsWith("Decimal")) {
- result = Double.class;
- } else if (edmTypeName.endsWith("Single")) {
- result = Double.class;
- } else if (edmTypeName.endsWith("Double")) {
- result = Double.class;
- } else if (edmTypeName.endsWith("Guid")) {
- result = String.class;
- } else if (edmTypeName.endsWith("Int16")) {
- result = Short.class;
- } else if (edmTypeName.endsWith("Int32")) {
- result = Integer.class;
- } else if (edmTypeName.endsWith("Int64")) {
- result = Long.class;
- } else if (edmTypeName.endsWith("Byte")) {
- result = Byte.class;
- } else if (edmTypeName.endsWith("String")) {
- result = String.class;
- }
-
- return result;
+ return javaTypeHandler.toJavaClass(edmTypeName);
}
/**
@@ -591,38 +408,7 @@ public static Class> toJavaClass(String edmTypeName) {
* @return The name of the corresponding Java class or scalar type.
*/
public static String toJavaTypeName(String edmTypeName) {
- String result = "Object";
- if (edmTypeName.endsWith("Binary")) {
- result = "byte[]";
- } else if (edmTypeName.endsWith("Boolean")) {
- result = "boolean";
- } else if (edmTypeName.endsWith("DateTime")) {
- result = "Date";
- } else if (edmTypeName.endsWith("DateTimeOffset")) {
- result = "Date";
- } else if (edmTypeName.endsWith("Time")) {
- result = "long";
- } else if (edmTypeName.endsWith("Decimal")) {
- result = "double";
- } else if (edmTypeName.endsWith("Single")) {
- result = "double";
- } else if (edmTypeName.endsWith("Double")) {
- result = "double";
- } else if (edmTypeName.endsWith("Guid")) {
- result = "String";
- } else if (edmTypeName.endsWith("Int16")) {
- result = "short";
- } else if (edmTypeName.endsWith("Int32")) {
- result = "int";
- } else if (edmTypeName.endsWith("Int64")) {
- result = "long";
- } else if (edmTypeName.endsWith("Byte")) {
- result = "byte";
- } else if (edmTypeName.endsWith("String")) {
- result = "String";
- }
-
- return result;
+ return javaTypeHandler.toJavaTypeName(edmTypeName);
}
}
diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
index fc34a1d449..181327f901 100644
--- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
+++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java
@@ -43,6 +43,8 @@
import org.restlet.ext.odata.internal.edm.Property;
import org.restlet.ext.odata.internal.edm.TypeUtils;
+import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty;
+
/**
* Handles Java reflection operations.
*
@@ -74,11 +76,9 @@ public class ReflectUtils {
*/
public static Class> getEntryClass(Feed feed) {
Class> result = null;
- if (feed != null && feed.getEntries() != null
- && !feed.getEntries().isEmpty()) {
+ if (feed != null && !isNullOrEmpty(feed.getEntries())) {
for (Entry entry : feed.getEntries()) {
- if (entry.getCategories() != null
- && !entry.getCategories().isEmpty()) {
+ if (!isNullOrEmpty(entry.getCategories())) {
Category category = entry.getCategories().get(0);
try {
result = Class.forName(TypeUtils
@@ -420,8 +420,7 @@ public static void setProperty(Object entity, Property property,
String propertyValue) throws Exception {
if (property.getType() != null) {
invokeSetter(entity, property.getNormalizedName(),
- TypeUtils.fromEdm(propertyValue, property.getType()
- .getName()));
+ TypeUtils.fromEdm(propertyValue, property.getType().getName()));
}
}
diff --git a/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java b/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java
new file mode 100644
index 0000000000..eebef3108c
--- /dev/null
+++ b/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2005-2014 Restlet
+ *
+ * The contents of this file are subject to the terms of one of the following
+ * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
+ * select the license that you prefer but you may not use this file except in
+ * compliance with one of these Licenses.
+ *
+ * You can obtain a copy of the Apache 2.0 license at
+ * http://www.opensource.org/licenses/apache-2.0
+ *
+ * You can obtain a copy of the EPL 1.0 license at
+ * http://www.opensource.org/licenses/eclipse-1.0
+ *
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ *
+ * Alternatively, you can obtain a royalty free commercial license with less
+ * limitations, transferable or non-transferable, directly at
+ * http://restlet.com/products/restlet-framework
+ *
+ * Restlet is a registered trademark of Restlet S.A.S.
+ */
+
+package org.restlet.engine.util;
+
+import java.util.Collection;
+
+/**
+ * Util class for collections.
+ *
+ * @author Thierry Boileau
+ */
+public class CollectionsUtils {
+
+ /**
+ * Indicates if the given collection is either null or empty.
+ *
+ * @param collection
+ * The collection.
+ * @return True if the collection is null of empty.
+ */
+ public static boolean isNullOrEmpty(Collection> collection) {
+ return collection == null || collection.isEmpty();
+ }
+}