dk.cloudcreate.essentials.components.eventsourced.aggregates.stateful.StatefulAggregateInstanceFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eventsourced-aggregates Show documentation
Show all versions of eventsourced-aggregates Show documentation
This library focuses on providing different flavors of eventsourced aggregrates
The newest version!
/*
* Copyright 2021-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dk.cloudcreate.essentials.components.eventsourced.aggregates.stateful;
import dk.cloudcreate.essentials.components.eventsourced.aggregates.Aggregate;
import dk.cloudcreate.essentials.components.eventsourced.aggregates.stateful.classic.AggregateRoot;
import dk.cloudcreate.essentials.shared.reflection.Reflector;
import org.objenesis.*;
import org.objenesis.instantiator.ObjectInstantiator;
import java.lang.reflect.Modifier;
import java.util.concurrent.*;
import static dk.cloudcreate.essentials.shared.FailFast.requireNonNull;
import static dk.cloudcreate.essentials.shared.MessageFormatter.msg;
/**
* Factory that helps the {@link StatefulAggregateRepository}/{@link StatefulAggregateInMemoryProjector} to create an instance of a given {@link Aggregate}.
*
* @see #reflectionBasedAggregateRootFactory()
* @see ReflectionBasedAggregateInstanceFactory
* @see #objenesisAggregateRootFactory()
* @see ObjenesisAggregateInstanceFactory
*/
public interface StatefulAggregateInstanceFactory {
/**
* Create an instance of the {@link Aggregate}
*
* @param id the id value
* @param aggregateType the {@link Aggregate} implementation type
* @param the type of aggregate id
* @param the {@link Aggregate} implementation type
* @return new aggregate instance
*/
AGGREGATE create(ID id, Class aggregateType);
/**
* Returns a {@link StatefulAggregateInstanceFactory} that calls the default no-arguments constructor on the concrete {@link Aggregate} type to
* create a new instance of the {@link Aggregate}
*
* @return a {@link StatefulAggregateInstanceFactory} that calls the default no-arguments constructor on the concrete {@link Aggregate} type
*/
static StatefulAggregateInstanceFactory reflectionBasedAggregateRootFactory() {
return new ReflectionBasedAggregateInstanceFactory();
}
/**
* Returns a {@link StatefulAggregateInstanceFactory} that uses {@link Objenesis} to create a new instance of the {@link Aggregate}
* Please note: Objenesis doesn't initialize fields nor call any constructors, so you {@link Aggregate} design needs to take
* this into consideration.
* All concrete aggregates that extends {@link AggregateRoot} have been prepared to be initialized by {@link Objenesis}
*
* @return a {@link StatefulAggregateInstanceFactory} that uses {@link Objenesis} to create a new instance of the {@link Aggregate}
*/
static StatefulAggregateInstanceFactory objenesisAggregateRootFactory() {
return new ObjenesisAggregateInstanceFactory();
}
/**
* {@link StatefulAggregateInstanceFactory} that calls the default no-arguments constructor on the concrete {@link Aggregate} type to
* create a new instance of the {@link Aggregate}
*/
class ReflectionBasedAggregateInstanceFactory implements StatefulAggregateInstanceFactory {
@Override
public AGGREGATE create(ID id, Class aggregateType) {
requireNonNull(id, "You must provide an id value");
requireNonNull(aggregateType, "You must provide an aggregateTypeClass");
var reflector = Reflector.reflectOn(aggregateType);
var defaultNoArgsConstructor = reflector.getDefaultConstructor();
if (defaultNoArgsConstructor.isPresent() && Modifier.isPublic(defaultNoArgsConstructor.get().getModifiers())) {
return reflector.newInstance();
} else if (reflector.hasMatchingConstructorBasedOnArguments(id)) {
return reflector.newInstance(id);
} else {
throw new IllegalArgumentException(msg("Couldn't find default constructor nor a constructor that accepts an aggregateId of type {}", id.getClass().getName()));
}
}
}
/**
* {@link StatefulAggregateInstanceFactory} that uses {@link Objenesis} to create a new instance of the {@link Aggregate}
* Please note: Objenesis doesn't initialize fields nor call any constructors, so you {@link Aggregate} design needs to take
* this into consideration.
* All concrete aggregates that extends {@link AggregateRoot} have been prepared to be initialized by {@link Objenesis}
*/
class ObjenesisAggregateInstanceFactory implements StatefulAggregateInstanceFactory {
private Objenesis objenesis;
private final ConcurrentMap, ObjectInstantiator>> instantiatorMap = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
@Override
public AGGREGATE create(ID id, Class aggregateType) {
requireNonNull(aggregateType, "You must provide an aggregateType");
if (objenesis == null) {
objenesis = new ObjenesisStd();
}
return (AGGREGATE) instantiatorMap.computeIfAbsent(aggregateType,
objenesis::getInstantiatorOf)
.newInstance();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy