package fr.openwide.core.jpa.config.spring.convert.converter;
import java.io.Serializable;
import java.util.Collections;
import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import fr.openwide.core.jpa.business.generic.model.GenericEntity;
import fr.openwide.core.jpa.business.generic.service.IEntityService;
/**
* Converts a String to a GenericEntity.
* Only matches if String.class can be converted to the target GenericEntity key type.
*/
public class StringToGenericEntitySpringConverter implements ConditionalGenericConverter {
private final ConversionService conversionService;
private final IEntityService entityService;
public StringToGenericEntitySpringConverter(ConversionService conversionService, IEntityService entityService) {
this.conversionService = conversionService;
this.entityService = entityService;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, GenericEntity.class));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
/*
* NOTE: for the official javac to infer types properly, the GenericEntity below must be left as a raw type.
* Eclipse JDT works fine without this hack.
*/
return canConvertKey(sourceType.getType(), (Class<? extends GenericEntity>) targetType.getType());
}
private <K extends Serializable & Comparable<K>, E extends GenericEntity<K, ?>>
boolean canConvertKey(Class<?> sourceType, Class<E> targetType) {
Class<K> keyType = GenericEntityTypeResolver.resolveKeyTypeParameter(targetType);
if (keyType != null) {
return this.conversionService.canConvert(sourceType, keyType);
} else {
return false;
}
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
String string = (String) source;
/*
* NOTE: for the official javac to infer types properly, the GenericEntity below must be left as a raw type.
* Eclipse JDT works fine without this hack.
*/
return convert(string, (Class<? extends GenericEntity>) targetType.getType());
}
private <K extends Serializable & Comparable<K>, E extends GenericEntity<K, ?>>
E convert(String source, Class<E> targetType) {
Class<K> keyType = GenericEntityTypeResolver.resolveKeyTypeParameter(targetType);
K id = convertKey(source, keyType);
E entity = entityService.getEntity(targetType, id);
if (entity == null) {
throw new RuntimeException("The entity for key " + id + " was not found");
} else {
return entity;
}
}
private <K extends Serializable & Comparable<K>>
K convertKey(String source, Class<K> targetKeyType) {
K id = conversionService.convert(source, targetKeyType);
if (id == null) {
throw new RuntimeException("The converted entity id was null");
} else {
return id;
}
}
}