I want to return object in constructor where I can assign values to new object
Code
Abstract Class:
public abstract class Models implements Serializable {
public Models(Object id) throws Exception {
this.find(id);
}
public <T extends Models> T find(Object id) throws Exception {
Map<String, T> data = new HashMap<>();
Long idSerialized = Long.parseLong(String.valueOf(id));
hibernateContext(
session -> data.put(
"obj",
(T) session.get(this.getClass(), idSerialized)
)
);
return data.get("obj");
}
}
child class:
public class Users extends Models implements Serializable {
public Users(Object id) throws Exception {
super(id);
this.encrypted_field = "password";
}
}
Related
I'm using ValueObjects to reduce primitive obesssion. To avoid unnecessary annotations on the mappers, I also use a special ValueObjectMapper. Normally, the mapping would look like this:
#Mapper
abstract class MyMapper {
#Mapping(target = "id", source = "id.value")
abstract TargetClass map(SourceClass source);
}
Because of the ValueObjectMapper, I can do without the annotation:
#Mapper(uses = ValueObjectMapper.class)
abstract class MyMapper {
abstract TargetClass map(SourceClass source);
}
For this to work, all value objects must implement this generic ValueObject interface:
interface ValueObject<T> {
T getValue();
}
The ValueObjectMapper looks like this:
class ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
}
This all works like a charm. However, a problem occurred when I wanted to further convert the result of the ValueOjbectMapper. A UUID should also be converted into a string. Then I got this error message:
incompatible types: inference variable T has incompatible bounds
The generated source code looks like this. Unfortunately it does not hand over the result to the map(UUID) method:
class MyMapperImpl extends MyMapper {
#Override
TargetClass map(SourceClass source) {
if ( source == null ) {
return null;
}
String id = null;
id = ValueObjectMapper.mapToValue( source.getId() );
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TargetClass targetClass = new TargetClass( id );
return targetClass;
}
}
It seems that MapStruct is not able to further process the result of the ValueObjectMapper. Have I made a mistake or is this a bug of MapStruct?
Here is the complete code:
package valueobject;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.UUID;
interface ValueObject<T> {
T getValue();
}
#Mapper(uses = ValueObjectMapper.class)
abstract class MyMapper {
abstract TargetClass map(SourceClass source);
String map(UUID uuid) {
return uuid.toString();
}
}
class ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
}
class SomeId implements ValueObject<UUID> {
private final UUID value;
public SomeId(UUID value) {
this.value = value;
}
#Override
public UUID getValue() {
return value;
}
}
class SourceClass {
private final SomeId id;
public SourceClass(SomeId id) {
this.id = id;
}
public SomeId getId() {
return id;
}
}
class TargetClass {
private final String id;
public TargetClass(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
public class Main {
public static void main(String[] args) {
MyMapper mapper = Mappers.getMapper(MyMapper.class);
SomeId id = new SomeId(UUID.fromString("F0E11AE8-6510-4F4D-B4D4-96C11A891606"));
SourceClass source = new SourceClass(id);
TargetClass target = mapper.map(source);
System.out.println("target: id='" + target.getId() + "'");
}
}
I'm developing a service oriented platform for retrieving, creating and updating entities from DB.
The point here is that every single java entity extends AbstractEntity, so for example, I have,
MyCar extends AbstractEntity implements Serializable
This AbstractEntity has common fields (such as id or audit ones).
So I have already developed a GenericReadService that, receiving a classname and a parameterMap, can read any entity and creates a EntityActionResult<T> including a List<T extends AbstractEntity>.
My problem comes when trying to transform that T type into something like <K extends GenericDTO>, as the client asking doesn't know AbstractEntity (obvious) but only GenericDTO. Doing this for safety and modularization.
So, now, I'm stuck on transforming the ListResponse<T> to a ReturnList<K extends GenericDTO>, as I don't find the way for knowing which K class should apply for each T.
This is what I actually have written:
private GenericEntityActionResult transform (EntityActionResult result) {
AsnGenericEntityActionResult r = new AsnGenericEntityActionResult();
if (result.getCode() == EntityActionResult.Code.ENTITY || result.getCode() == EntityActionResult.Code.ENTITY_LIST ) {
r.setCode(AsnGenericEntityActionResult.Code.OK);
List <? extends GenericDTO> list = new ArrayList<>();
if (result.getEntity() != null) {
//transform this entity into DTO
//<b>SOMETHING LIKE list.add(result.getEntity());</b>
} else if (result.getList() != null && !result.getList().isEmpty()) {
for (AbstractEntity a:result.getList()) {
//transform this entity into DTO
//<b>SOMETHING LIKE list.add(result.getEntity());</b>
//list.add(result.getEntity());
}
}
r.setList(list);
}
return r;
I´m obviously stuck on the SOMETHING LIKE, but can't find a proper way of doing so.
I thought about creating a abstract <T extends GenericDTO> transformToDTO() method on AbstractEntity, but can't do it since there are lots (and i mean hundreds) of Entities extending AbstractEntity and this client-service approach is a new development for some Entities, not the whole system.
Any clever ideas?
You can try to use the Java Introspection API or some more robust library on top of this API like apache commons beanutils or even more powerful bean mapping library like Dozer or something newer see
Following example demonstrating the basic technique, only raw introspection and reflection with two compatible POJO beans.
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
class Tranformation {
public static void main(String[] args) {
MyCar car = new MyCar();
car.setId("id01");
car.setName("Komodo");
car.setMadeIn("Jakarta");
CarDTO dto = toDto(CarDTO.class, car);
System.out.println(dto);
}
public <E extends AbstractEntity, D extends GenericDTO> D toDto(Class<D> dtoClass, E entity) {
if (null == entity) {
throw new NullPointerException("Entity can not be null");
}
try {
final D ret = dtoClass.newInstance();
BeanInfo dtoBeanInfo = Introspector.getBeanInfo(dtoClass);
final Map<String, PropertyDescriptor> mapping = Arrays.stream(dtoBeanInfo.getPropertyDescriptors())
.collect(Collectors.toMap(PropertyDescriptor::getName, Function.identity()));
final BeanInfo entityBeanInfo = Introspector.getBeanInfo(entity.getClass());
Arrays.stream(entityBeanInfo.getPropertyDescriptors()).forEach(src -> {
if (!"class".equals(src.getName())) {
PropertyDescriptor dst = mapping.get(src.getName());
if (null != dst) {
try {
dst.getWriteMethod().invoke(ret, src.getReadMethod().invoke(entity, null));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}
});
return ret;
} catch (InstantiationException | IntrospectionException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
public static class GenericDTO {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class CarDTO extends GenericDTO {
private String madeIn;
public String getMadeIn() {
return madeIn;
}
public void setMadeIn(String madeIn) {
this.madeIn = madeIn;
}
#Override
public String toString() {
return String.format("CarDTO [id=%s, name=%s, madeIn=%s]", getId(), getName(), madeIn);
}
}
public static class AbstractEntity implements Serializable {
private static final long serialVersionUID = 70377433289079231L;
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class MyCar extends AbstractEntity {
private static final long serialVersionUID = 8702011501211036271L;
private String madeIn;
public String getMadeIn() {
return madeIn;
}
public void setMadeIn(String madeIn) {
this.madeIn = madeIn;
}
}
}
Outputs:
CarDTO [id=id01, name=Komodo, madeIn=Jakarta]
I want to get rid of the following code duplication within the MyFacadeBean. Consider the following situation:
public class FacadeBean implements Facade {
#EJB
private CrudService crudService;
#Inject
private FirstAssembler firstAssembler;
#Inject
private SecondAssembler secondAssembler;
#Inject
private ThirdAssembler thridAssembler;
#Inject
private FourthAssembler fourthAssembler;
#Override
public void save(FirstValue value) {
FirstEntity entity = this.firstAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(SecondValue value) {
SecondEntity entity = this.secondAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(ThirdValue value) {
ThirdEntity entity = this.thirdAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(FourthValue value) {
FourthEntity entity = this.fourthAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
public interface MyFacade {
void save(FirstValue value);
void save(SecondValue value);
}
With the CrudService:
public interface CrudService {
void persist(Object entity);
}
#Stateless
#Local(CrudService.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudServiceBean implements CrudService {
public static final String PERSISTENCE_UNIT_NAME = "my_persistence_unit";
private EntityManager entityManager;
#PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public void persist(Object entity) {
this.entityManager.persist(entity);
}
}
With the following assemblers:
public class FirstAssembler extends AbstractAssembler<FirstEntity> {
public FirstEntity transformToEntity(FirstValue value) {
if (value == null)
return null;
FirstEntity entity = new FirstEntity();
transformAbstractValueToAbstractObject(value, entity);
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
public class SecondAssembler extends AbstractAssembler<SecondEntity> {
public SecondEntity transformToEntity(SecondValue value) {
if (value == null)
return null;
SecondEntity entity = new SecondEntity();
transformAbstractValueToAbstractObject(value, entity);
entity.setTransactionType(value.getTransactionType());
entity.setValueDate(value.getValueDate());
return entity;
}
}
public abstract class AbstractAssembler<T extends AbstractEntity> {
protected void transformAbstractValueToAbstractObject(AbstractValue value, T object) {
object.setUniqueId(value.getUniqueId());
object.setNominalAmountValue(value.getNominalAmountValue());
}
}
With the following entities:
#Entity
public class FirstEntity extends AbstractEntity {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private Long id;
#Column(name = "START_DATE")
#Temporal(TemporalType.DATE)
private Date startDate;
#Column(name = "FIXED_RATE")
#Digits(integer = 1, fraction = 10)
private BigDecimal fixedRate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public BigDecimal getFixedRate() {
return fixedRate;
}
public void setFixedRate(BigDecimal fixedRate) {
this.fixedRate = fixedRate;
}
}
#Entity
public class SecondEntity extends AbstractEntity {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private Long id;
#Column(name = "VALUE_DATE")
#Temporal(TemporalType.DATE)
private Date valueDate;
#Column(name = "TRANSACTION_TYPE")
#Enumerated(EnumType.STRING)
private TransactionType transactionType;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getValueDate() {
return valueDate;
}
public void setValueDate(Date valueDate) {
this.valueDate = valueDate;
}
public TransactionType getTransactionType() {
return transactionType;
}
public void setTransactionType(TransactionType transactionType) {
this.transactionType = transactionType;
}
}
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "TRANSACTION_NOM_AMOUNT_VALUE")
#Digits(integer = 18, fraction = 5)
#Min(0)
private BigDecimal nominalAmountValue;
public BigDecimal getNominalAmountValue() {
return nominalAmountValue;
}
public void setNominalAmountValue(BigDecimal nominalAmountValue) {
this.nominalAmountValue = nominalAmountValue;
}
}
I tried the following approach:
public class FacadeBean implements Facade {
#Inject
private Assembler assembler;
#Inject
private AssemblerFactory assemblerFactory;
#Override
public <T extends AbstractValue> void save(T value) {
Assembler assembler = assemblerFactory.createAssembler(value);
AbstractEntity entity = assembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
Problems are the AssemblerFactoryImpl and the AssemblerImpl in which I have to do instanceOf checks and castings...
Another idea would be to let the value know which transformer to use (or how to transform). But I want the value to be "dumb".
#Glenn Lane
public AbstractValue save(AbstractValue value) {
AbstractAssembler<AbstractValue, AbstractEntity> assembler = new FirstAssembler();
AbstractEntity entity = assembler.transformToEntity(value);
AbstractValue result = assembler.transformToValue(entity);
return result;
}
does not work, because of
Type mismatch: cannot convert from FirstAssembler to AbstractAssembler
I'm posting this as a separate answer, since I don't really think there's anything wrong with having a save method for every AbstractValue type.
First we'll establish your base value class for this example. I'm using an interface just so we don't muddy the waters. Your AbstractValue interface:
public interface AbstractValue
{
int getUniqueId();
double getNominalValue();
<T> T accept(AbstractValueVisitor<T> visitor);
}
And the "visitor interface":
public interface AbstractValueVisitor<T>
{
T visit(FirstValue value);
T visit(SecondValue value);
T visit(ThirdValue value);
T visit(FourthValue value);
}
I know you don't want intelligence baked into AbstractValue, but we are going to add one specification... that all concrete implementations of AbstractValue (all four) implement the accept method exactly this way:
#Override
public <T> T accept(AbstractValueVisitor<T> visitor)
{
return visitor.visit(this);
}
So that method is implemented four times: in all four value classes, exactly the same way. Because the visitor interface is aware of all concrete implementations, the appropriate method will be called for each particular value type. All three of these parts put together is the "visitor pattern".
Now we'll make an entity factory. Its job is to create the appropriate AbstractEntity when provided an AbstractValue:
public class AbstractEntityFactory
implements AbstractValueVisitor<AbstractEntity>
{
private static final AbstractEntityFactory INSTANCE;
static
{
INSTANCE = new AbstractEntityFactory();
}
// Singleton pattern
private AbstractEntityFactory()
{
}
public static AbstractEntity create(AbstractValue value)
{
if (value == null)
{
return null;
}
AbstractEntity e = value.accept(INSTANCE);
e.setNominalValue(value.getNominalValue());
e.setUniqueId(value.getUniqueId());
return e;
}
#Override
public AbstractEntity visit(FirstValue value)
{
FirstEntity entity = new FirstEntity();
// Set all properties specific to FirstEntity
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
#Override
public AbstractEntity visit(SecondValue value)
{
SecondEntity entity = new SecondEntity();
// Set all properties specific to SecondEntity
entity.setTransactionType(value.getTransactionType());
entity.setValueDate(value.getValueDate());
return entity;
}
#Override
public AbstractEntity visit(ThirdValue value)
{
ThirdEntity entity = new ThirdEntity();
// Set all properties specific to ThirdEntity
return entity;
}
#Override
public AbstractEntity visit(FourthValue value)
{
FourthEntity entity = new FourthEntity();
// Set all properties specific to FourthEntity
return entity;
}
}
Now your facade implementation takes an AbstractValue, and you got that one save method you're looking for:
public class FacadeBean implements Facade
{
#EJB
private CrudService crudService;
#Override
public void save(AbstractValue value)
{
AbstractEntity entity = AbstractEntityFactory.create(value);
crudService.persist(entity);
}
}
Because your AbstractValue now follows the visitor pattern, you can do all sorts of polymorphic behavior. Such as:
public class AbstractValuePrinter implements AbstractValueVisitor<Void>
{
private final Appendable out;
public AbstractValuePrinter(Appendable out)
{
this.out = out;
}
private void print(String s)
{
try
{
out.append(s);
out.append('\n');
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
#Override
public Void visit(FirstValue value)
{
print("I'm a FirstValue!");
print("Being a FirstValue is groovy!");
return null;
}
#Override
public Void visit(SecondValue value)
{
print("I'm a SecondValue!");
print("Being a SecondValue is awesome!");
return null;
}
#Override
public Void visit(ThirdValue value)
{
print("I'm a ThirdValue!");
print("Meh.");
return null;
}
#Override
public Void visit(FourthValue value)
{
print("I'm a ThirdValue!");
print("Derp.");
return null;
}
}
In this example, this visitor isn't returning anything... it's "doing" something, so we'll just set the return value as Void, since it's non-instantiatable. Then you print the value simply:
// (value must not be null)
value.accept(new AbstractValuePrinter(System.out));
Finally, the coolest part of the visitor pattern (in my opinion): you add FifthValue. You add the new method to your visitor interface:
T visit(FifthValue value);
And suddenly, you can't compile. You must address the lack of this handling in two places: AbstractEntityFactory and AbstractValuePrinter. Which is great, because you should consider it in those places. Doing class comparisons (with either instanceof or rinde's solution of a class-to-factory map) is likely to "miss" the new value type, and now you have runtime bugs... especially if you're doing 100 different things with these value types.
Anyhoo, I didn't want to get into this, but there you go :)
Use a generic method with a bound type parameter in order to spare yourself the repetition:
public <T extends AbstractValue> T save(T value) {...}
Within the method body, you'll be able to reference the argument value with all methods pertaining to AbstractValue.
Notes
Since your save methods seem to be overrides in this example, you might need to change the design of the parent class or interface too.
You could also use a generic class to start with (instead of a generic method in a non-necessarily generic class), depending on your use case.
I think a problem in your code is that the generic type of AbstractAssembler is that of the output of the transform method, not the input. If you change it as follows:
public abstract class AbstractAssembler<T extends AbstractValue> {
protected void transformAbstractValueToAbstractObject(AbstractEntity entity, T value) {
entity.setUniqueId(value.getUniqueId());
entity.setNominalAmountValue(value.getNominalAmountValue());
}
public abstract AbstractEntity transformToEntity(T value);
}
Then you can change the FacadeBean to the following.
public class FacadeBean {
#EJB
private CrudService crudService;
final Map<Class<?>, AbstractAssembler<?>> knownAssemblers;
FacadeBean() {
knownAssemblers = new LinkedHashMap<>();
knownAssemblers.put(FirstValue.class, new FirstAssembler());
knownAssemblers.put(SecondValue.class, new SecondAssembler());
// add more assemblers here
}
public <T extends AbstractValue> void save(T value, Class<T> type) {
#SuppressWarnings("unchecked") // safe cast
final AbstractAssembler<T> assembler =
(AbstractAssembler<T>) knownAssemblers.get(type);
final AbstractEntity entity = assembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
Notice that I changed the signature of the save(..) method such that we have the type of the object that needs to be saved. With this type we can simply lookup the right assembler that should be used. And because the assembler is now generic on its input type, we can do a safe cast (be careful to keep your map consistent).
This implementation avoids duplication of code as you only need one save method. The use of the instanceof operator is prevented by changing the generic type of AbstractAssembler and storing all assemblers in a map.
The assemblers can look like this:
public class FirstAssembler extends AbstractAssembler<FirstValue> {
#Override
public FirstEntity transformToEntity(FirstValue value) {
final FirstEntity entity = new FirstEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
public class SecondAssembler extends AbstractAssembler<SecondValue> {
#Override
public SecondEntity transformToEntity(SecondValue value) {
final SecondEntity entity = new SecondEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
return entity;
}
}
Note: I'm not familiar with Java beans so you probably have to adapt the code a little if you want to use the #Injected assemblers instead of calling the constructors directly.
You're getting close to gold-plating here, but there is a bit of reduction you can do, specifically the null-check and calling the common field-setting method from each extension.
public abstract class AbstractAssembler<V extends AbstractValue, E extends AbstractEntity>
{
public final E transformToEntity(V value)
{
if (value == null)
{
return null;
}
E entity = createEntity(value);
entity.setUniqueId(value.getUniqueId());
entity.setNominalAmountValue(value.getNominalAmountValue());
return entity;
}
/**
* #return
* Appropriate entity object, with the fields not common to all AbstractEntity
* already set
*/
protected abstract E createEntity(V value);
}
And then the extended assembler:
public class FirstAssembler extends AbstractAssembler<FirstValue, FirstEntity>
{
#Override
protected FirstEntity createEntity(FirstValue value)
{
FirstEntity entity = new FirstEntity();
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
If you really want a single factory class to handle all your values/entities, I would look into the visitor pattern, enhanced with a generic type parameter on the visitor interface (and the entity/value accept methods return a type based on the visiting interface). I won't show an example here simply because I don't think it's warranted in your case.
You can have one save method from the point of view of the classes that save those values, but you still have to implement three individual save methods.
Implement a class with all three save methods. For example:
public class ValuePersister {
#Inject
private Assembler1 assembler1;
#Inject
private Assembler2 assembler2;
#Inject
private Assembler3 assembler3;
public Value1 save(Value1 value1, CrudService crudService) {
Entity1 entity1 = assembler1.transformToObject(value1);
crudService.persist(entity1);
return assembler1.transformToValue(entity1);
}
public Value2 save(Value2 value2, CrudService crudService) {
Entity2 entity2 = assembler2.transformToObject(value2);
crudService.persist(entity2);
return assembler2.transformToValue(entity2);
}
public Value3 save(Value3 value3, CrudService crudService) {
Entity3 entity3 = assembler3.transformToObject(value3);
crudService.persist(entity3);
return assembler3.transformToValue(entity3);
}
}
Add an abstract method to AbstractValue:
public abstract AbstractValue save(ValuePersister valuePersister, CrudService crudService);
Implement that method in each class that extends AbstractValue:
#Override
public AbstractValue save(ValuePersister valuePersister, CrudService crudService) {
return valuePersister.save(this, crudService);
}
Inject ValuePersister and implement your original generic save method:
#Inject
private ValuePersister valuePersister;
#Override
public AbstractValue save(AbstractValue value) {
return value.save(valuePersister, crudService)
}
I have an abstract class that I use to define some abstract methods that will be shared between the subclasses (This is what I understand to be the correct usage of abstract classes. Since this for a set of classes that are very similar I decided to go with an abstract class rather than an interface.)
public abstract class DomainService<T extends Domain> {
abstract public void insert(T object) throws ValidationException;
abstract public void delete(T object) throws EntityNotFoundException;
abstract public List<T> fetchAll();
}
T is the domain class that is related to and all the domain classes have a common superclass called Domain
public abstract class Domain implements Serializable {
private static final long serialVersionUID = 8868922239517301371L;
private static Logger log = LoggerFactory.getLogger(Domain.class);
public Domain() {
}
public List<String> getColumnMembers() {
Field[] declaredFields = this.getClass().getDeclaredFields();
List<String> declaredFieldsNames = new ArrayList<String>(declaredFields.length);
for (Field field : declaredFields) {
if (Modifier.isStatic(field.getModifiers()) || !field.isAnnotationPresent(Column.class)) {
continue;
}
declaredFieldsNames.add(field.getName());
}
return declaredFieldsNames;
}
public abstract Object getPrimaryKey();
}
And each Domain has a DomainAccess class that access the tables in the database and all these have a common superclass called DomainAccess for the shared methodds
public abstract class DomainAccess<T extends Domain> {
protected abstract Logger getLogger();
protected DatabaseFacade db;
protected Class<T> domainClass;
#Inject
public DomainAccess(DatabaseFacade databaseFacade, Class<T> domainClass) {
this.db = databaseFacade;
this.domainClass = domainClass;
}
#SuppressWarnings("unchecked")
public T fetchByPrimaryKey(Object primaryKey) {
return (T) db.find(domainClass, primaryKey);
}
public boolean exists(T object) {
return fetchByPrimaryKey(object.getPrimaryKey()) == null ? false : true;
}
public void save(T object) {
db.save(object);
}
public void merge(T object) {
db.merge(object);
}
public void delete(T object) {
db.remove(object);
}
public void saveOrUpdate(T object) {
if (exists(object)) {
merge(object);
} else {
save(object);
}
}
public void deleteByPrimaryKey(T object) throws EntityNotFoundException {
Object primaryKey = object.getPrimaryKey();
T objectToDelete = fetchByPrimaryKey(primaryKey);
if (objectToDelete != null) {
getLogger().debug("There was no entry found with primary key: " + primaryKey);
throw new EntityNotFoundException("No entry was found with specified primary key [" + primaryKey + "]");
} else {
getLogger().debug("Deleting entry with id: " + primaryKey);
delete(objectToDelete);
}
}
#SuppressWarnings("unchecked")
public List<T> getResultList(String hql, String... parameters) {
TypedQuery<T> query = db.createTypedQuery(hql, domainClass);
for (int i = 0; i < parameters.length; i++) {
query.setParameter(i + 1, parameters[i]);
}
return query.getResultList();
}
#SuppressWarnings("unchecked")
public T getSingleResult(String hql, String... parameters) {
TypedQuery<T> query = db.createTypedQuery(hql, domainClass);
for (int i = 1; i <= parameters.length; i++) {
query.setParameter(i, parameters[i - 1]);
}
return query.getSingleResult();
}
}
My question other than any remarks you may have on what you see here, is the following:
The delete method in the DomainService is the same for each subclass, i.e.
UserService:
#Transactional
#Override
public void delete(User user) throws EntityNotFoundException {
userAccess.deleteByPrimaryKey(user);
}
DepartmentService:
#Transactional
#Override
public void delete(Department department) throws EntityNotFoundException {
departmentAccess.deleteByPrimaryKey(department);
}
So I was thinking of moving it to the abstract parent class. But to do that I would have to define the DomainAccess there, something like this at a guess
public abstract class DomainService<T extends Domain> {
protected DomainAccess<T> domainAccess;
protected DomainService(DomainAccess<T> domainAccess) {
this.domainAccess = domainAccess;
}
abstract public void insert(T object) throws ValidationException;
public void delete(T object) throws ValidationException {
domainAccess.deleteByPrimaryKey(user);
}
abstract public List<T> fetchAll();
}
with the DomainService passed in the subclass constructor
#Inject
public UserService(UserAccess userAccess) {
super(userAccess);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
this.validator = factory.getValidator();
}
but if I do that then in the subclasses, let's say UserService a method I had
#Override
public List<User> fetchAll() {
return userAccess.fetchAllUsers();
}
would have to become like this
#Override
public List<User> fetchAll() {
return ((UserAccess)domainAccess).fetchAllUsers();
}
and that would have to be done everytime I used a specific method to the subclass.
That seems wrong. Are there any pointers or ways of thinking to how much you can use generics or abstraction?
I'm trying to prepare an interface i want to implement for Datamodel-Classes.Therefor i want to use an enum inside the interface so i know i need to implement it later.
Example:
public interface MyModelInterface {
public enum Field;
public Object get(Field field);
public void set(Field field, Object value);
}
The expected implementation:
public class MyModel implements MyModelInterface {
public enum Field {
ID("id"),
Name1("Name1"),
Name2("Name2");
private String field;
private Field(String field) {
this.field = field;
}
}
public Object get(Field field) {
//...
}
public void set(Field field, Object value){
//...
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(MyModel.Field.ID));
System.out.println(myModel.get(MyModel.Field.Name1));
}
}
Since I don't know which fields the model will contain until I implement it.
I did some research and figured that enum can't be extended, so i am aware of that.
is there any way to archive this or any kind of workaround?
i don't want to use String Parameters on the getter/setter Methods to avoid using wrong values.
Thanks in advance for any suggestion.
Update:
So this is what worked for me: Splitting the interface/class in three parts, including an abstract class:
Interface:
public interface MyModelInterface<E extends Enum<E>> {
public Object get(E field);
public void set(E field, Object value);
}
Abstract Class:
public abstract class MyAbstractModel<E extends Enum<E>> implements MyModelInterface<E>{
protected final EnumMap<E, Object> fields;
public MyAbstractModel(Class<E> enumKlazz) {
fields = new EnumMap<>(enumKlazz);
}
#Override
public Object get(E field) {
return fields.get(field);
}
#Override
public void set(E field, Object value) {
this.fields.put(field, value);
}
}
Class(where i actually archive my goal):
public class MyModel extends MyAbstractModel<MyModel.Field> {
public MyModel() {
super(MyModel.Field.class);
}
public enum Field {
ID("ID"),
Name1("NAME1"),
Name2("NAME2"),
Age("AGE"),
;
private final String field;
private Field(String field) {
this.field = field;
}
public String getName() {
return field;
}
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(Field.Name1));
}
}
Interface fields are static and final implicitly.
What you could do is to have an interface method returning Enum<?>, and your classes implementing it.
For instance:
interface Foo {
public Enum<?> getEnum();
}
class Bar implements Foo {
enum Blah {
INSTANCE;
}
public Enum<?> getEnum() {
return Blah.INSTANCE;
}
}
Edit
Not completely sure I understand your question update, but here's a solution that will de-couple returning a specific enum instance from an enum, by means of two interfaces.
The example is self-contained in a Main class.
public class Main {
public static void main(String[] args) {
System.out.println(new Bar().getEnumField().name());
}
static interface IHasEnum {
public Enum<? extends IMyEnum> getEnumField();
}
static interface IMyEnum {
public Enum<? extends IMyEnum> getField();
}
static class Bar implements IHasEnum {
enum Blah implements IMyEnum {
DEFAULT_INSTANCE,
THE_FIELD;
public Enum<? extends IMyEnum> getField() {
return THE_FIELD;
}
}
public Enum<? extends IMyEnum> getEnumField() {
return Blah.DEFAULT_INSTANCE.getField();
}
}
}
Output
THE_FIELD
Note
The trick here is to add a "default" instance to the enum (DEFAULT_INSTANCE), so the getField method is an instance method, hence overriding the one declared in the IMyEnum interface.
Again, not entirely sure this addresses your issue.
What you are describing is an EnumMap<E, T> - which functions like an array, with that same get-
public class MyModelBase<E extends Enum<E>> {
private final Class<E> enumKlazz;
private final EnumMap<E, Object> fields;
public MyModelBase(Class<E> enumKlazz) {
this.enumKlazz = enumKlazz;
fields = new EnumMpa<>(enumKlazz);
}
public Object get(E field) {
return fields.get(field);
}
public void set(E field, Object value) {
fields.put(field, value);
}
}
enum UserField { id, surname, name, age };
MyModelBase<UserField> userModel = new MyModelBase<>(UserField.class);
userModel.set(UserField.surname, "X");
Because of type erasure the enum map needs the class. Above the enum class is also stored as field, as some static Enum methods need the enum class. For iterating, and so on.
Java generics will be the best solution.
Lets assume, you don't know the contents of the Field as mentioned.
Create a generic interface like this:
public interface MyModelInterface<T> {
public T get();
}
Then create a class Field like this:
public class Field {
private String id;
private String name1;
private String name2;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
and then your model class will look like
public class MyModel implements MyModelInterface<Field> {
#Override
public Field get() {
Field field = new Field();
field.setId("ID");
field.setName1("Name1");
field.setName2("Name2");
return field;
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get().getId());
System.out.println(myModel.get().getName1());
System.out.println(myModel.get().getName2());
}
}