Skip to content

Commit

Permalink
Allow the ListArrayType to support Set entity attributes #496
Browse files Browse the repository at this point in the history
  • Loading branch information
vladmihalcea committed Oct 17, 2022
1 parent 7b02229 commit 0502c8d
Show file tree
Hide file tree
Showing 24 changed files with 469 additions and 118 deletions.
Expand Up @@ -3,6 +3,9 @@
import com.vladmihalcea.hibernate.type.array.internal.AbstractArrayType;
import com.vladmihalcea.hibernate.type.array.internal.ListArrayTypeDescriptor;
import com.vladmihalcea.hibernate.type.util.Configuration;
import org.hibernate.usertype.DynamicParameterizedType;

import java.util.Properties;

/**
* Maps an {@link java.util.List} entity attribute on a PostgreSQL ARRAY column type.
Expand All @@ -11,7 +14,7 @@
*
* @author Vlad Mihalcea
*/
public class ListArrayType extends AbstractArrayType<Object> {
public class ListArrayType extends AbstractArrayType<Object> implements DynamicParameterizedType {

public static final ListArrayType INSTANCE = new ListArrayType();

Expand All @@ -30,4 +33,9 @@ public ListArrayType(Configuration configuration) {
public String getName() {
return "list-array";
}

@Override
public void setParameterValues(Properties parameters) {
((DynamicParameterizedType) getJavaTypeDescriptor()).setParameterValues(parameters);
}
}
Expand Up @@ -3,6 +3,7 @@
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
Expand Down Expand Up @@ -117,15 +118,15 @@ public static Object[] wrapArray(Object originalArray) {
array[i] = fromArray[i];
}
return array;
} else if (originalArray instanceof List) {
return ((List) originalArray).toArray();
} else if (originalArray instanceof Collection) {
return ((Collection) originalArray).toArray();
} else {
return (Object[]) originalArray;
}
}

/**
* Unwarp {@link Object[]} array to an array of the provided type
* Unwrap {@link Object[]} array to an array of the provided type
*
* @param originalArray original array
* @param arrayClass array class
Expand Down
Expand Up @@ -18,12 +18,18 @@ public class ListArrayTypeDescriptor extends AbstractArrayTypeDescriptor<Object>

private String sqlArrayType;

private Class entityClass;

private String propertyName;

private Class propertyClass;

public ListArrayTypeDescriptor() {
super(Object.class, new MutableMutabilityPlan<Object>() {
@Override
protected Object deepCopyNotNull(Object value) {
if (value instanceof List) {
Object[] array = ((List) value).toArray();
if (value instanceof Collection) {
Object[] array = ((Collection<Object>) value).toArray();
return ArrayUtil.asList((Object[]) ArrayUtil.deepCopy(array));
} else if (value.getClass().isArray()) {
Object[] array = (Object[]) value;
Expand Down Expand Up @@ -53,8 +59,8 @@ protected String getSqlArrayType() {
public Object unwrap(Object value, Class type, WrapperOptions options) {
if (value instanceof Object[]) {
return value;
} else if (value instanceof List) {
return super.unwrap(((List) value).toArray(), type, options);
} else if (value instanceof Collection) {
return super.unwrap(((Collection) value).toArray(), type, options);
} else {
throw new UnsupportedOperationException("The provided " + value + " is not a Object[] or List!");
}
Expand All @@ -63,9 +69,9 @@ public Object unwrap(Object value, Class type, WrapperOptions options) {
@Override
public Object wrap(Object value, WrapperOptions options) {
Object wrappedObject = super.wrap(value, options);
List list = null;
Collection list = null;
if (wrappedObject != null) {
list = new ArrayList();
list = newPropertyCollectionInstance();
if (wrappedObject instanceof Object[]) {
Object[] wrappedArray = (Object[]) wrappedObject;
Collections.addAll(list, wrappedArray);
Expand All @@ -84,8 +90,8 @@ public boolean areEqual(Object one, Object another) {
if (one == null || another == null) {
return false;
}
if (one instanceof List && another instanceof List) {
return ArrayUtil.isEquals(((List) one).toArray(), ((List) another).toArray());
if (one instanceof Collection && another instanceof Collection) {
return ArrayUtil.isEquals(((Collection) one).toArray(), ((Collection) another).toArray());
}
if (one instanceof Object[] && another instanceof Object[]) {
return ArrayUtil.isEquals(one, another);
Expand All @@ -96,9 +102,10 @@ public boolean areEqual(Object one, Object another) {

@Override
public void setParameterValues(Properties parameters) {
Class entityClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.ENTITY));
String property = parameters.getProperty(DynamicParameterizedType.PROPERTY);
Type memberGenericType = ReflectionUtils.getMemberGenericTypeOrNull(entityClass, property);
this.entityClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.ENTITY));
this.propertyName = parameters.getProperty(DynamicParameterizedType.PROPERTY);
this.propertyClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.RETURNED_CLASS));
Type memberGenericType = ReflectionUtils.getMemberGenericTypeOrNull(entityClass, propertyName);
if (memberGenericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) memberGenericType;

Expand Down Expand Up @@ -136,9 +143,17 @@ public void setParameterValues(Properties parameters) {
throw new UnsupportedOperationException("The " + arrayElementClass + " is not supported yet!");
}
}

} else {
throw new UnsupportedOperationException("The property " + property + " in the " + entityClass + " entity is not parameterized!");
throw new UnsupportedOperationException("The property " + propertyName + " in the " + entityClass + " entity is not parameterized!");
}
}

private Collection newPropertyCollectionInstance() {
if(List.class.isAssignableFrom(propertyClass)) {
return new ArrayList();
} else if(Set.class.isAssignableFrom(propertyClass)) {
return new LinkedHashSet();
}
throw new UnsupportedOperationException("The property " + propertyName + " in the " + entityClass + " entity is not supported by the ListArrayType!");
}
}
Expand Up @@ -117,6 +117,15 @@ public Void apply(EntityManager entityManager) {
event.setDateValues(Arrays.asList(date1, date2));
event.setTimestampValues(Arrays.asList(date1, date2));
event.setDecimalValues(Arrays.asList(BigDecimal.ONE, BigDecimal.ZERO));
event.setLocalDateTimeSetValues(
new LinkedHashSet<Date>(
Arrays.asList(
date1,
date1,
date2
)
)
);

entityManager.persist(event);

Expand Down Expand Up @@ -149,6 +158,16 @@ public Void apply(EntityManager entityManager) {
assertEquals(date2.getTime(), event.getTimestampValues().get(1).getTime());
assertArrayEquals(new BigDecimal[]{BigDecimal.ONE, BigDecimal.ZERO}, event.getDecimalValues().toArray());

assertEquals(
new HashSet<Date>(
Arrays.asList(
date1,
date2
)
),
event.getLocalDateTimeSetValues()
);

return null;
}
});
Expand Down Expand Up @@ -374,18 +393,19 @@ public Void apply(EntityManager entityManager) {

@Entity(name = "Event")
@TypeDefs({
@TypeDef(name = "uuid-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "string-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "int-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "long-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "boolean-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "double-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "date-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "timestamp-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "decimal-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "sensor-state-array", typeClass = ListArrayType.class, parameters = {
@Parameter(name = ListArrayType.SQL_ARRAY_TYPE, value = "sensor_state")}
)
@TypeDef(name = "uuid-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "string-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "int-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "long-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "boolean-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "double-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "date-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "timestamp-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "decimal-list-array", typeClass = ListArrayType.class),
@TypeDef(name = "sensor-state-array", typeClass = ListArrayType.class, parameters = {
@Parameter(name = ListArrayType.SQL_ARRAY_TYPE, value = "sensor_state")}
),
@TypeDef(name = "set-list-array", typeClass = ListArrayType.class)
})
@Table(name = "event")
public static class Event extends BaseEntity {
Expand Down Expand Up @@ -435,6 +455,13 @@ public static class Event extends BaseEntity {
@Column(name = "decimal_values", columnDefinition = "decimal[]")
private List<BigDecimal> decimalValues;

@Type(type = "set-list-array")
@Column(
name = "localdatetime_set_values",
columnDefinition = "timestamp[]"
)
private Set<Date> localDateTimeSetValues;

public List<UUID> getSensorIds() {
return sensorIds;
}
Expand Down Expand Up @@ -514,6 +541,15 @@ public List<BigDecimal> getDecimalValues() {
public void setDecimalValues(List<BigDecimal> decimalValues) {
this.decimalValues = decimalValues;
}

public Set<Date> getLocalDateTimeSetValues() {
return localDateTimeSetValues;
}

public Event setLocalDateTimeSetValues(Set<Date> localDateTimeSetValues) {
this.localDateTimeSetValues = localDateTimeSetValues;
return this;
}
}

public enum SensorState {
Expand Down
Expand Up @@ -3,6 +3,9 @@
import com.vladmihalcea.hibernate.type.array.internal.AbstractArrayType;
import com.vladmihalcea.hibernate.type.array.internal.ListArrayTypeDescriptor;
import com.vladmihalcea.hibernate.type.util.Configuration;
import org.hibernate.usertype.DynamicParameterizedType;

import java.util.Properties;

/**
* Maps an {@link java.util.List} entity attribute on a PostgreSQL ARRAY column type.
Expand All @@ -11,7 +14,7 @@
*
* @author Vlad Mihalcea
*/
public class ListArrayType extends AbstractArrayType<Object> {
public class ListArrayType extends AbstractArrayType<Object> implements DynamicParameterizedType {

public static final ListArrayType INSTANCE = new ListArrayType();

Expand All @@ -30,4 +33,9 @@ public ListArrayType(Configuration configuration) {
public String getName() {
return "list-array";
}

@Override
public void setParameterValues(Properties parameters) {
((DynamicParameterizedType) getJavaTypeDescriptor()).setParameterValues(parameters);
}
}
Expand Up @@ -3,6 +3,7 @@
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
Expand Down Expand Up @@ -117,15 +118,15 @@ public static Object[] wrapArray(Object originalArray) {
array[i] = fromArray[i];
}
return array;
} else if (originalArray instanceof List) {
return ((List) originalArray).toArray();
} else if (originalArray instanceof Collection) {
return ((Collection) originalArray).toArray();
} else {
return (Object[]) originalArray;
}
}

/**
* Unwarp {@link Object[]} array to an array of the provided type
* Unwrap {@link Object[]} array to an array of the provided type
*
* @param originalArray original array
* @param arrayClass array class
Expand Down
Expand Up @@ -18,12 +18,18 @@ public class ListArrayTypeDescriptor extends AbstractArrayTypeDescriptor<Object>

private String sqlArrayType;

private Class entityClass;

private String propertyName;

private Class propertyClass;

public ListArrayTypeDescriptor() {
super(Object.class, new MutableMutabilityPlan<Object>() {
@Override
protected Object deepCopyNotNull(Object value) {
if (value instanceof List) {
Object[] array = ((List) value).toArray();
if (value instanceof Collection) {
Object[] array = ((Collection<Object>) value).toArray();
return ArrayUtil.asList((Object[]) ArrayUtil.deepCopy(array));
} else if (value.getClass().isArray()) {
Object[] array = (Object[]) value;
Expand Down Expand Up @@ -53,8 +59,8 @@ protected String getSqlArrayType() {
public Object unwrap(Object value, Class type, WrapperOptions options) {
if (value instanceof Object[]) {
return value;
} else if (value instanceof List) {
return super.unwrap(((List) value).toArray(), type, options);
} else if (value instanceof Collection) {
return super.unwrap(((Collection) value).toArray(), type, options);
} else {
throw new UnsupportedOperationException("The provided " + value + " is not a Object[] or List!");
}
Expand All @@ -63,9 +69,9 @@ public Object unwrap(Object value, Class type, WrapperOptions options) {
@Override
public Object wrap(Object value, WrapperOptions options) {
Object wrappedObject = super.wrap(value, options);
List list = null;
Collection list = null;
if (wrappedObject != null) {
list = new ArrayList();
list = newPropertyCollectionInstance();
if (wrappedObject instanceof Object[]) {
Object[] wrappedArray = (Object[]) wrappedObject;
Collections.addAll(list, wrappedArray);
Expand All @@ -84,8 +90,8 @@ public boolean areEqual(Object one, Object another) {
if (one == null || another == null) {
return false;
}
if (one instanceof List && another instanceof List) {
return ArrayUtil.isEquals(((List) one).toArray(), ((List) another).toArray());
if (one instanceof Collection && another instanceof Collection) {
return ArrayUtil.isEquals(((Collection) one).toArray(), ((Collection) another).toArray());
}
if (one instanceof Object[] && another instanceof Object[]) {
return ArrayUtil.isEquals(one, another);
Expand All @@ -96,9 +102,10 @@ public boolean areEqual(Object one, Object another) {

@Override
public void setParameterValues(Properties parameters) {
Class entityClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.ENTITY));
String property = parameters.getProperty(DynamicParameterizedType.PROPERTY);
Type memberGenericType = ReflectionUtils.getMemberGenericTypeOrNull(entityClass, property);
this.entityClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.ENTITY));
this.propertyName = parameters.getProperty(DynamicParameterizedType.PROPERTY);
this.propertyClass = ReflectionUtils.getClass(parameters.getProperty(DynamicParameterizedType.RETURNED_CLASS));
Type memberGenericType = ReflectionUtils.getMemberGenericTypeOrNull(entityClass, propertyName);
if (memberGenericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) memberGenericType;

Expand Down Expand Up @@ -136,9 +143,17 @@ public void setParameterValues(Properties parameters) {
throw new UnsupportedOperationException("The " + arrayElementClass + " is not supported yet!");
}
}

} else {
throw new UnsupportedOperationException("The property " + property + " in the " + entityClass + " entity is not parameterized!");
throw new UnsupportedOperationException("The property " + propertyName + " in the " + entityClass + " entity is not parameterized!");
}
}

private Collection newPropertyCollectionInstance() {
if(List.class.isAssignableFrom(propertyClass)) {
return new ArrayList();
} else if(Set.class.isAssignableFrom(propertyClass)) {
return new LinkedHashSet();
}
throw new UnsupportedOperationException("The property " + propertyName + " in the " + entityClass + " entity is not supported by the ListArrayType!");
}
}

0 comments on commit 0502c8d

Please sign in to comment.