Updated Branches: refs/heads/camel-2.11.x 9795a32f1 -> 4aeb44a84 refs/heads/camel-2.12.x c388c53e8 -> b347ad0b3 refs/heads/master 952ec4b04 -> e494f725b
CAMEL-7001: Avro dataformat classloading issue in OSGi. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e494f725 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e494f725 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e494f725 Branch: refs/heads/master Commit: e494f725b3325cc0c405f875f14afdd3c65fd70e Parents: 952ec4b Author: Claus Ibsen <davscl...@apache.org> Authored: Sat Nov 23 13:39:45 2013 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sat Nov 23 13:39:45 2013 +0100 ---------------------------------------------------------------------- .../camel/dataformat/avro/AvroDataFormat.java | 62 +++++++++++--------- .../avro/AvroMarshalAndUnmarshallTest.java | 3 +- 2 files changed, 36 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e494f725/components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java ---------------------------------------------------------------------- diff --git a/components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java b/components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java index 3e1ed05..5c158d9 100644 --- a/components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java +++ b/components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java @@ -37,11 +37,14 @@ import org.apache.camel.CamelException; import org.apache.camel.Exchange; import org.apache.camel.spi.DataFormat; import org.apache.camel.support.ServiceSupport; +import org.apache.camel.util.ObjectHelper; public class AvroDataFormat extends ServiceSupport implements DataFormat, CamelContextAware { + private static final String GENERIC_CONTAINER_CLASSNAME = GenericContainer.class.getName(); private CamelContext camelContext; - private Schema schema; + private Object schema; + private transient Schema actualSchema; private String instanceClassName; public AvroDataFormat() { @@ -61,8 +64,14 @@ public class AvroDataFormat extends ServiceSupport implements DataFormat, CamelC @Override protected void doStart() throws Exception { - if (instanceClassName != null) { - schema = loadDefaultSchema(instanceClassName, camelContext); + if (schema != null) { + if (schema instanceof Schema) { + actualSchema = (Schema) schema; + } else { + actualSchema = loadSchema(schema.getClass().getName()); + } + } else if (instanceClassName != null) { + actualSchema = loadSchema(instanceClassName); } } @@ -71,56 +80,55 @@ public class AvroDataFormat extends ServiceSupport implements DataFormat, CamelC // noop } - public Schema getSchema(Exchange exchange, Object graph) throws Exception { - if (schema == null) { - if (graph != null && graph instanceof GenericContainer) { - return loadDefaultSchema(graph.getClass().getName(), exchange.getContext()); - } else { - throw new CamelException("There is not schema for avro marshaling / unmarshaling"); - } - } - return schema; + // the getter/setter for Schema is Object type in the API + + public Object getSchema() { + return actualSchema != null ? actualSchema : schema; } public void setSchema(Object schema) { - if (schema instanceof Schema) { - this.schema = (Schema) schema; - } else { - throw new IllegalArgumentException("The argument for setDefaultInstance should be subClass of " + Schema.class.getName()); - } + this.schema = schema; + } + + public String getInstanceClassName() { + return instanceClassName; } public void setInstanceClass(String className) throws Exception { instanceClassName = className; } - public String getInstanceClassName() { - return instanceClassName; - } + protected Schema loadSchema(String className) throws CamelException, ClassNotFoundException { + // must use same class loading procedure to ensure working in OSGi + Class<?> instanceClass = camelContext.getClassResolver().resolveMandatoryClass(className); + Class<?> genericContainer = camelContext.getClassResolver().resolveMandatoryClass(GENERIC_CONTAINER_CLASSNAME); - protected Schema loadDefaultSchema(String className, CamelContext context) throws CamelException, ClassNotFoundException { - Class<?> instanceClass = context.getClassResolver().resolveMandatoryClass(className); - if (GenericContainer.class.isAssignableFrom(instanceClass)) { + if (genericContainer.isAssignableFrom(instanceClass)) { try { Method method = instanceClass.getMethod("getSchema", new Class[0]); - return (Schema) method.invoke(instanceClass.newInstance(), new Object[0]); + return (Schema) method.invoke(camelContext.getInjector().newInstance(instanceClass)); } catch (Exception ex) { throw new CamelException("Error calling getSchema on " + instanceClass, ex); } } else { - throw new CamelException("Class " + instanceClass + " must be instanceof org.apache.avro.generic.GenericContainer"); + throw new CamelException("Class " + instanceClass + " must be instanceof " + GENERIC_CONTAINER_CLASSNAME); } } public void marshal(Exchange exchange, Object graph, OutputStream outputStream) throws Exception { - DatumWriter<Object> datum = new SpecificDatumWriter<Object>(getSchema(exchange, graph)); + // the schema should be from the graph class name + Schema useSchema = actualSchema != null ? actualSchema : loadSchema(graph.getClass().getName()); + + DatumWriter<Object> datum = new SpecificDatumWriter<Object>(useSchema); Encoder encoder = EncoderFactory.get().binaryEncoder(outputStream, null); datum.write(graph, encoder); encoder.flush(); } public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception { - DatumReader<GenericRecord> reader = new SpecificDatumReader<GenericRecord>(getSchema(exchange, null)); + ObjectHelper.notNull(actualSchema, "schema", this); + + DatumReader<GenericRecord> reader = new SpecificDatumReader<GenericRecord>(actualSchema); Decoder decoder = DecoderFactory.get().binaryDecoder(inputStream, null); Object result = reader.read(null, decoder); return result; http://git-wip-us.apache.org/repos/asf/camel/blob/e494f725/components/camel-avro/src/test/java/org/apache/camel/dataformat/avro/AvroMarshalAndUnmarshallTest.java ---------------------------------------------------------------------- diff --git a/components/camel-avro/src/test/java/org/apache/camel/dataformat/avro/AvroMarshalAndUnmarshallTest.java b/components/camel-avro/src/test/java/org/apache/camel/dataformat/avro/AvroMarshalAndUnmarshallTest.java index 2bb7d3c..99b4c36 100644 --- a/components/camel-avro/src/test/java/org/apache/camel/dataformat/avro/AvroMarshalAndUnmarshallTest.java +++ b/components/camel-avro/src/test/java/org/apache/camel/dataformat/avro/AvroMarshalAndUnmarshallTest.java @@ -54,8 +54,7 @@ public class AvroMarshalAndUnmarshallTest extends CamelTestSupport { }); fail("Expect the exception here"); } catch (Exception ex) { - assertTrue("Expect FailedToCreateRouteException", ex instanceof FailedToCreateRouteException); - assertTrue("Get a wrong reason", ex.getCause() instanceof IllegalArgumentException); + // expected } }