Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added ExtendedUpcaster interface, which allow for extra flexibility

The UpcasterChain implementations will recognize this interface and invoke the
upcast(SerializedType, SerializedObject) method instead of the
upcast(SerializedType). This allows the implementation to decide the type based
on the SerializedObject's contents

In the next major release, this method will be included in the Upcaster
interface itself.

Issue #AXON-220 Fixed
  • Loading branch information...
commit 471223c704611319f06a56a8715f89a2539ea2fb 1 parent 6f05be0
@abuijze abuijze authored
View
19 core/src/main/java/org/axonframework/upcasting/AbstractUpcasterChain.java
@@ -101,17 +101,18 @@ protected AbstractUpcasterChain(ConverterFactory converterFactory, List<Upcaster
* Each item in the returned List of SerializedObject must match the given list of <code>targetTypes</code>. These
* types are returned by the invocation of {@link Upcaster#upcast(org.axonframework.serializer.SerializedType)}.
*
- * @param upcaster The upcaster to perform the upcasting with
- * @param sourceObject The SerializedObject to upcast
- * @param targetTypes The types expected in the returned List of SerializedObject
- * @param context The container of properties of the Domain Event Message being upcast
- * @param <T> The representation type expected by the upcaster
+ * @param upcaster The upcaster to perform the upcasting with
+ * @param sourceObject The SerializedObject to upcast
+ * @param targetTypes The types expected in the returned List of SerializedObject
+ * @param context The container of properties of the Domain Event Message being upcast
+ * @param <T> The representation type expected by the upcaster
* @return The List of SerializedObject representing the upcast <code>sourceObject</code>
*/
protected abstract <T> List<SerializedObject<?>> doUpcast(Upcaster<T> upcaster, SerializedObject<?> sourceObject,
List<SerializedType> targetTypes,
UpcastingContext context);
+ @SuppressWarnings("unchecked")
private List<SerializedObject> upcastInternal(List<SerializedObject> serializedObjects,
Iterator<Upcaster> upcasterIterator,
UpcastingContext context) {
@@ -122,7 +123,13 @@ protected AbstractUpcasterChain(ConverterFactory converterFactory, List<Upcaster
Upcaster<?> currentUpcaster = upcasterIterator.next();
for (SerializedObject serializedObject : serializedObjects) {
if (currentUpcaster.canUpcast(serializedObject.getType())) {
- List<SerializedType> upcastTypes = currentUpcaster.upcast(serializedObject.getType());
+ List<SerializedType> upcastTypes;
+ if (currentUpcaster instanceof ExtendedUpcaster) {
+ upcastTypes = ((ExtendedUpcaster) currentUpcaster).upcast(serializedObject.getType(),
+ serializedObject);
+ } else {
+ upcastTypes = currentUpcaster.upcast(serializedObject.getType());
+ }
upcastObjects.addAll(doUpcast(currentUpcaster, serializedObject, upcastTypes, context));
} else {
upcastObjects.add(serializedObject);
View
49 core/src/main/java/org/axonframework/upcasting/ExtendedUpcaster.java
@@ -0,0 +1,49 @@
+package org.axonframework.upcasting;
+
+import org.axonframework.serializer.SerializedObject;
+import org.axonframework.serializer.SerializedType;
+
+import java.util.List;
+
+/**
+ * Extension of the Upcaster interface that allows type upcasting to be based on the contents of the
+ * serialized object. UpcasterChain implementations should invoke the {@link #upcast(org.axonframework.serializer.SerializedType,
+ * org.axonframework.serializer.SerializedObject)} on upcasters that implement this interface, instead of {@link
+ * #upcast(org.axonframework.serializer.SerializedType)}
+ *
+ * @param <T> The data format that this upcaster uses to represent the event
+ * @author Allard Buijze
+ * @since 2.2
+ */
+public interface ExtendedUpcaster<T> extends Upcaster<T> {
+
+ /**
+ * Upcast the given <code>serializedType</code> into its new format. Generally, this involves increasing the
+ * revision. Sometimes, it is also necessary to alter the type's name (in case of a renamed class, for example).
+ * The order and the size of the list returned has to match with the order and size of the list of the upcast
+ * IntermediateRepresentations by this upcaster.
+ * <p/>
+ * Unlike the {@link #upcast(org.axonframework.serializer.SerializedType)} method, this gives you access to the
+ * serialized object to upcast. This may be used to choose the SerializedType based on the contents of a Message's
+ * payload.
+ * <p/>
+ * Implementations aware of the ExtendedUpcaster interface must use this method instead of {@link
+ * #upcast(org.axonframework.serializer.SerializedType)}
+ *
+ * @param serializedType The serialized type to upcast
+ * @param intermediateRepresentation The intermediate representation of the object to define the type for
+ * @return the upcast serialized type
+ */
+ List<SerializedType> upcast(SerializedType serializedType, SerializedObject<T> intermediateRepresentation);
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Implementing this method is optional.
+ *
+ * @throws java.lang.UnsupportedOperationException if the implementation requires the intermediate representation
+ * to upcast the serialized type.
+ */
+ @Override
+ List<SerializedType> upcast(SerializedType serializedType);
+}
View
6 core/src/main/java/org/axonframework/upcasting/Upcaster.java
@@ -76,9 +76,15 @@
* revision. Sometimes, it is also necessary to alter the type's name (in case of a renamed class, for example).
* The order and the size of the list returned has to match with the order and size of the list of the upcast
* IntermediateRepresentations by this upcaster.
+ * <p/>
+ * To base the type on the actual contents of the Serialized Object, implement the {@link
+ * org.axonframework.upcasting.ExtendedUpcaster} interface instead.
*
* @param serializedType The serialized type to upcast
* @return the upcast serialized type
+ *
+ * @see org.axonframework.upcasting.ExtendedUpcaster#upcast(org.axonframework.serializer.SerializedType,
+ * org.axonframework.serializer.SerializedObject)
*/
List<SerializedType> upcast(SerializedType serializedType);
}
View
79 core/src/test/java/org/axonframework/upcasting/LazyUpcasterChainTest.java
@@ -72,6 +72,39 @@ public void testToBeConstructed() {
verify(thirdUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
}
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testUpcastingChainWithExtendedUpcaster() {
+ Upcaster<String> firstUpcaster = spy(new StubUpcaster("1", "2"));
+ Upcaster<String> secondUpcaster = spy(new StubExtendedUpcaster("2", "3"));
+ Upcaster<String> thirdUpcaster = spy(new StubUpcaster("never", "ever"));
+ LazyUpcasterChain testSubject = new LazyUpcasterChain(Arrays.<Upcaster>asList(firstUpcaster,
+ thirdUpcaster,
+ secondUpcaster));
+
+ List<SerializedObject> actualResult = testSubject.upcast(
+ new SimpleSerializedObject<String>("object", String.class, "type", "1"), null);
+ // the second upcaster accessed the serialized object, so we expect a call here
+ verify(firstUpcaster).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(secondUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(thirdUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ assertEquals(4, actualResult.size());
+ assertEquals("3", actualResult.get(0).getType().getRevision());
+ assertEquals("3", actualResult.get(1).getType().getRevision());
+ assertEquals("3", actualResult.get(2).getType().getRevision());
+ assertEquals("3", actualResult.get(3).getType().getRevision());
+ verify(firstUpcaster).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(secondUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(thirdUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ assertEquals("upcast upcast object", actualResult.get(0).getData().toString());
+ assertEquals("upcast upcast object", actualResult.get(1).getData().toString());
+ assertEquals("upcast upcast object", actualResult.get(2).getData().toString());
+ assertEquals("upcast upcast object", actualResult.get(3).getData().toString());
+ verify(firstUpcaster).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(secondUpcaster, times(2)).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ verify(thirdUpcaster, never()).upcast(isA(SerializedObject.class), isA(List.class), any(UpcastingContext.class));
+ }
+
private class StubUpcaster implements Upcaster<String> {
private final String workingRevision;
@@ -110,4 +143,50 @@ public boolean canUpcast(SerializedType serializedType) {
return Arrays.asList(upcastType, upcastType);
}
}
+
+ private class StubExtendedUpcaster implements ExtendedUpcaster<String> {
+
+ private final String workingRevision;
+ private final String newRevision;
+
+ public StubExtendedUpcaster(String workingRevision, String newRevision) {
+ this.workingRevision = workingRevision;
+ this.newRevision = newRevision;
+ }
+
+ @Override
+ public boolean canUpcast(SerializedType serializedType) {
+ return workingRevision.equals(serializedType.getRevision());
+ }
+
+ @Override
+ public Class<String> expectedRepresentationType() {
+ return String.class;
+ }
+
+ @Override
+ public List<SerializedObject<?>> upcast(SerializedObject<String> intermediateRepresentation,
+ List<SerializedType> expectedTypes, UpcastingContext context) {
+ List<SerializedObject<?>> upcastObjects = new ArrayList<SerializedObject<?>>(expectedTypes.size());
+ for (SerializedType expectedType : expectedTypes) {
+ SerializedObject<String> upcastObject = new SimpleSerializedObject<String>(
+ "upcast " + intermediateRepresentation.getData(), String.class, expectedType);
+ upcastObjects.add(upcastObject);
+ }
+ return upcastObjects;
+ }
+
+ @Override
+ public List<SerializedType> upcast(SerializedType serializedType,
+ SerializedObject<String> intermediateRepresentation) {
+ assertEquals("upcast object", intermediateRepresentation.getData());
+ SerializedType upcastType = new SimpleSerializedType(serializedType.getName(), newRevision);
+ return Arrays.asList(upcastType, upcastType);
+ }
+
+ @Override
+ public List<SerializedType> upcast(SerializedType serializedType) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+ }
}
View
31 core/src/test/java/org/axonframework/upcasting/SimpleUpcasterChainTest.java
@@ -16,7 +16,20 @@
package org.axonframework.upcasting;
+import org.axonframework.common.io.IOUtils;
+import org.axonframework.eventstore.jpa.SimpleSerializedDomainEventData;
import org.axonframework.serializer.ConverterFactory;
+import org.axonframework.serializer.SerializedObject;
+import org.axonframework.serializer.Serializer;
+import org.axonframework.serializer.SimpleSerializedObject;
+import org.joda.time.DateTime;
+import org.junit.*;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
/**
* @author Allard Buijze
@@ -27,4 +40,22 @@
protected UpcasterChain createUpcasterChain(ConverterFactory converterFactory, Upcaster... upcasters) {
return new SimpleUpcasterChain(converterFactory, upcasters);
}
+
+ @Test
+ public void testEmptyUpcasterChain() {
+ UpcasterChain chain = new SimpleUpcasterChain(Collections.<Upcaster>emptyList());
+ final SimpleSerializedObject serializedObject = new SimpleSerializedObject<String>("Data", String.class,
+ "test", "0");
+ List<SerializedObject> result = chain.upcast(serializedObject,
+ new SerializedDomainEventUpcastingContext(
+ new SimpleSerializedDomainEventData(
+ "eventId", "aggregateId", 0, DateTime.now(), "test", "0",
+ "Data".getBytes(IOUtils.UTF8),
+ "meta".getBytes(IOUtils.UTF8)
+ ), mock(Serializer.class))
+ );
+
+ assertEquals(Collections.<SerializedObject>singletonList(serializedObject), result);
+ assertSame(serializedObject, result.get(0));
+ }
}
View
3  core/src/test/java/org/axonframework/upcasting/UpcasterChainTest.java
@@ -28,6 +28,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import static org.junit.Assert.*;
@@ -104,7 +105,7 @@ public void testUpcastObject_WithTypeConversion() {
UpcasterChain chain = createUpcasterChain(mockConverterFactory, mockUpcaster12);
List<SerializedObject> actualObjects = chain.upcast(object1, upcastingContext);
- for (SerializedObject actual : actualObjects) {
+ for (SerializedObject actual : actualObjects) {
// chaining may be lazy
actual.getData();
}
Please sign in to comment.
Something went wrong with that request. Please try again.