public interface AggregateRoot extends Serializable {

} @SuppressWarnings("serial")
@Data
public class AggregateRootHistory implements Serializable {

	private final List<UnitOfWork> unitsOfWork;
	private final Set<UnitOfWork> persisted;

	public AggregateRootHistory() {
		this.unitsOfWork = new LinkedList<>();
		this.persisted = new LinkedHashSet<>();
	}

	public List<Event> getAllEvents() {
       return getEventsAfterUntil(0, Long.MAX_VALUE);
	}

	public List<Event> getEventsAfterUntil(long afterVersion, long untilVersion){
		List<Event> events = new LinkedList<>();
		for (UnitOfWork t : unitsOfWork) {
			if (t.getVersion() > afterVersion && t.getVersion() <= untilVersion){
				for (Event event : t.getEvents()) {
					events.add(event);
				}
			}
		}
		return events;
	}
	
	public List<Event> getEventsUntil(long version){
		List<Event> events = new LinkedList<>();
		for (UnitOfWork t : unitsOfWork) {
			if (t.getVersion() <= version){
				for (Event event : t.getEvents()) {
					events.add(event);
				}
			}
		}
		return events;
	}
	
	public Long getLastVersion() {
		return unitsOfWork.size()==0 ? 0 : unitsOfWork.get(unitsOfWork.size()-1).getVersion();
	}

	public void add(final UnitOfWork transaction) {
		checkNotNull(transaction);
		unitsOfWork.add(transaction);
	}

	public UnitOfWork getLastUnitOfWork() {
		return unitsOfWork.get(unitsOfWork.size()-1);
	}

    public List<UnitOfWork> getPendingOfPersistence() {
        return Lists.newLinkedList(Sets.difference(Sets.newLinkedHashSet(unitsOfWork), persisted));
    }

    public void markAsPersisted(UnitOfWork uow) {
        checkArgument(unitsOfWork.contains(uow), "unitOfWork must be part of this AggregateRootHistory in order to be marked as persisted");
        persisted.add(uow);
    }

} @SuppressWarnings("serial")
@Value
public class Snapshot<A extends AggregateRoot> implements Serializable {
	
	private A aggregateInstance;
	private Long version;

} @SuppressWarnings("serial")
@Value
public class UnitOfWork implements Comparable<UnitOfWork>, Serializable {

    final UUID id;
	final Command command;
	final List<? extends Event> events;
	final long version;
	
	public UnitOfWork(UUID id, Command command, Long version, List<? extends Event> events) {
	    checkNotNull(id, "id cannot be null");
	    checkNotNull(command, "command cannot be null");
		checkArgument(command.getTargetVersion()>=0, "target version must be >= 0");
		checkArgument(version>0, "invalid version");
		checkNotNull(events, "events cannot be null");
		for (Event e: events){
			checkNotNull(e, "event within events list cannot be null");
		}
		this.id = id;
		this.command = command;
		this.version = version;
		this.events = events;
	}
	
	public static UnitOfWork create(UUID id, Command command, List<? extends Event> newEvents) {
		checkNotNull(command.getTargetVersion(), "target version cannot be null");
		checkArgument(command.getTargetVersion()>=0, "target version must be >= 0");
		return new UnitOfWork(id, command, command.getTargetVersion()+1, newEvents);
	}
	
	public List<Event> getEvents(){
		List<Event> result = new LinkedList<>();
		for (Event event : events) {
			result.add(event);
		}
		return result;
	}
	
	public int compareTo(UnitOfWork other) {
		if (version < other.version) {
			return -1;
		} else if (version > other.version) {
			return 1;
		}
		return 0;
	}

	public Long getTargetVersion() {
		return command.getTargetVersion();
	}
} @Value
public static class CreateInventoryItem implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    Long targetVersion = 0L;
} @Value
public static class DecreaseInventory implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
    Long targetVersion;
} @Value
public static class IncreaseInventory implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
    Long targetVersion;
} @Value
public static class InventoryDecreased implements Event {
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
} @Value
public static class InventoryIncreased implements Event {
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
} @Data
public static class InventoryItemAggregateRoot implements AggregateRoot {

    UUID id;
    String description;
    Integer available = 0;

    public void on(InventoryItemCreated event) {
        this.id = event.id;
        this.description = event.description;
        this.available = 0;
    }

    public void on(InventoryIncreased event) {
        this.available = this.available + event.howMany;
    }

    public void on(InventoryDecreased event) {
        this.available = this.available - event.howMany;
    }
        
    public boolean isAvailable(int howMany) {
        return getAvailable() - howMany >= 0;
    }

} @Value
public static class InventoryItemCreated implements Event {
    @NonNull
    UUID id;
    @NonNull
    String description;
} @AllArgsConstructor
public class HzGsonSerializer implements ByteArraySerializer<Object> {

    final Gson gson ;
    final int type ;
    final Class<?> clazz;

	@Override
	public void destroy() {
	}

	@Override
	public int getTypeId() {
		return type;
	}

	@Override
	public Object read(byte[] data) throws IOException {
		String json = new String(data);
		Object result = gson.fromJson(json, clazz);
		return result;
	}

	@Override
	public byte[] write(Object object) throws IOException {
		String json = gson.toJson(object, clazz);
		return json.getBytes();
	}
 
} @AllArgsConstructor
public class HzGsonTypedSerializer implements ByteArraySerializer<Object> {

    final Gson gson ;
    final int typeId ;
    final Type type;;

	@Override
	public void destroy() {
	}

	@Override
	public int getTypeId() {
		return typeId;
	}

	@Override
	public Object read(byte[] data) throws IOException {
		String json = new String(data);
		Object result = gson.fromJson(json, type);
		return result;
	}

	@Override
	public byte[] write(Object object) throws IOException {
		String json = gson.toJson(object, type);
		return json.getBytes();
	}
 
}
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.myeslib.core.AggregateRoot;
import org.myeslib.core.data.AggregateRootHistory;
import org.myeslib.core.data.Snapshot;
import org.myeslib.core.data.UnitOfWork;
import org.myeslib.example.SampleDomain.CreateInventoryItem;
import org.myeslib.example.SampleDomain.DecreaseInventory;
import org.myeslib.example.SampleDomain.IncreaseInventory;
import org.myeslib.example.SampleDomain.InventoryDecreased;
import org.myeslib.example.SampleDomain.InventoryIncreased;
import org.myeslib.example.SampleDomain.InventoryItemAggregateRoot;
import org.myeslib.example.SampleDomain.InventoryItemCreated;
import org.myeslib.util.hazelcast.HzGsonSerializer;
import org.myeslib.util.hazelcast.HzGsonTypedSerializer;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import com.hazelcast.config.SerializerConfig;
package org.myeslib.example.hazelcast.infra;




public class InventoryItemSerializersConfigFactory {

	private final Gson gson;

	final List<Class<? extends Serializable>> classes = Arrays.asList(AggregateRootHistory.class, UnitOfWork.class, 
			AggregateRoot.class,
			InventoryItemAggregateRoot.class,
			CreateInventoryItem.class, InventoryItemCreated.class, 
			IncreaseInventory.class, InventoryIncreased.class,
			DecreaseInventory.class, InventoryDecreased.class