Skip to content

Commit

Permalink
#230 Create collection types that can be combined / #128 Refactor pro…
Browse files Browse the repository at this point in the history
…perty builders

- Arrays, inline arrays and collections are now based on property types which can be constructed from other property paths
- Introduce an enum set type
- Refactor the property builders (remove inheritance among builders, rename methods for default values to be more clear)
- Lift requirement that the collections in properties are always unmodifiable; to be seen in more depth with #379
  • Loading branch information
ljacqu committed Sep 12, 2023
1 parent 20941f3 commit 4b0be9f
Show file tree
Hide file tree
Showing 51 changed files with 2,126 additions and 844 deletions.
31 changes: 31 additions & 0 deletions src/main/java/ch/jalu/configme/internal/ArrayUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ch.jalu.configme.internal;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Array;

/**
* Array utils.
*/
public final class ArrayUtils {

private ArrayUtils() {
}

/**
* Creates an array of the given size whose component type is the specified class. An exception is thrown
* if the component type is a primitive type, or void.
*
* @param component the component class the array must have
* @param size the size the array must have
* @param <T> type of array elements
* @return array of the given type and size
*/
@SuppressWarnings("unchecked")
public static <T> T @NotNull [] createArrayForReferenceType(@NotNull Class<T> component, int size) {
if (component.isPrimitive()) {
throw new IllegalArgumentException("The component type may not be a primitive type, but got: " + component);
}
return (T[]) Array.newInstance(component, size);
}
}
44 changes: 6 additions & 38 deletions src/main/java/ch/jalu/configme/properties/ArrayProperty.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
package ch.jalu.configme.properties;

import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder;
import ch.jalu.configme.properties.types.ArrayPropertyType;
import ch.jalu.configme.properties.types.PropertyType;
import ch.jalu.configme.resource.PropertyReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Objects;
import java.util.function.IntFunction;

/**
* Property whose value is an array of a given type.
*
* @param <T> the type of the elements in the array
*/
public class ArrayProperty<T> extends BaseProperty<T[]> {

private final PropertyType<T> type;
private final IntFunction<T[]> arrayProducer;
public class ArrayProperty<T> extends TypeBasedProperty<T[]> {

/**
* Constructor.
Expand All @@ -30,36 +23,11 @@ public class ArrayProperty<T> extends BaseProperty<T[]> {
*/
public ArrayProperty(@NotNull String path, T @NotNull [] defaultValue, @NotNull PropertyType<T> type,
@NotNull IntFunction<T[]> arrayProducer) {
super(path, defaultValue);
Objects.requireNonNull(type, "type");
Objects.requireNonNull(arrayProducer, "arrayProducer");
this.type = type;
this.arrayProducer = arrayProducer;
}

@Override
protected T @Nullable [] getFromReader(@NotNull PropertyReader reader,
@NotNull ConvertErrorRecorder errorRecorder) {
Object object = reader.getObject(this.getPath());
if (object instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) object;
return collection.stream()
.map(elem -> type.convert(elem, errorRecorder))
.filter(Objects::nonNull)
.toArray(arrayProducer);
}
return null;
this(path, new ArrayPropertyType<>(type, arrayProducer), defaultValue);
}

@Override
public @NotNull Object toExportValue(T @NotNull [] value) {
Object[] array = new Object[value.length];

for (int i = 0; i < array.length; i++) {
array[i] = this.type.toExportValue(value[i]);
}

return array;
@SafeVarargs
public ArrayProperty(@NotNull String path, @NotNull PropertyType<T[]> type, T @NotNull ... defaultValue) {
super(path, defaultValue, type);
}

}
31 changes: 5 additions & 26 deletions src/main/java/ch/jalu/configme/properties/InlineArrayProperty.java
Original file line number Diff line number Diff line change
@@ -1,46 +1,25 @@
package ch.jalu.configme.properties;

import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder;
import ch.jalu.configme.properties.inlinearray.InlineArrayConverter;
import ch.jalu.configme.resource.PropertyReader;
import ch.jalu.configme.properties.types.InlineArrayPropertyType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

/**
* Array property which reads and stores its value as one String in which the elements
* are separated by a delimiter.
*
* @param <T> the array element type
*/
public class InlineArrayProperty<T> extends BaseProperty<T[]> {

private final InlineArrayConverter<T> inlineConverter;
public class InlineArrayProperty<T> extends TypeBasedProperty<T[]> {

/**
* Constructor.
*
* @param path the path of the property
* @param defaultValue the default value of the property
* @param inlineConverter the inline converter to use
* @param inlineConverter the inline array property type
*/
public InlineArrayProperty(@NotNull String path, T @NotNull [] defaultValue,
@NotNull InlineArrayConverter<T> inlineConverter) {
super(path, defaultValue);
Objects.requireNonNull(inlineConverter, "inlineConverter");
this.inlineConverter = inlineConverter;
}

@Override
protected T @Nullable [] getFromReader(@NotNull PropertyReader reader,
@NotNull ConvertErrorRecorder errorRecorder) {
String value = reader.getString(getPath());
return value == null ? null : inlineConverter.fromString(value);
}

@Override
public Object toExportValue(T @NotNull [] value) {
return inlineConverter.toExportValue(value);
@NotNull InlineArrayPropertyType<T> inlineConverter) {
super(path, defaultValue, inlineConverter);
}
}
57 changes: 20 additions & 37 deletions src/main/java/ch/jalu/configme/properties/ListProperty.java
Original file line number Diff line number Diff line change
@@ -1,69 +1,52 @@
package ch.jalu.configme.properties;

import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder;
import ch.jalu.configme.properties.types.ListPropertyType;
import ch.jalu.configme.properties.types.PropertyType;
import ch.jalu.configme.resource.PropertyReader;
import org.jetbrains.annotations.NotNull;

import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* List property of a configurable type. The lists are immutable.
* List property of a configurable type. The default value is immutable.
*
* @param <T> the property type
* @param <E> the entry type
*/
public class ListProperty<T> extends BaseProperty<List<T>> {

private final PropertyType<T> type;
public class ListProperty<E> extends TypeBasedProperty<List<E>> {

/**
* Constructor.
*
* @param path the path of the property
* @param type the property type
* @param entryType the entry type
* @param defaultValue the entries in the list of the default value
*/
@SafeVarargs
public ListProperty(@NotNull String path, @NotNull PropertyType<T> type, @NotNull T @NotNull ... defaultValue) {
this(path, type, Arrays.asList(defaultValue));
public ListProperty(@NotNull String path, @NotNull PropertyType<E> entryType,
@NotNull E @NotNull ... defaultValue) {
this(path, entryType, Arrays.asList(defaultValue));
}

/**
* Constructor.
*
* @param path the path of the property
* @param type the property type
* @param entryType the entry type
* @param defaultValue the default value of the property
*/
public ListProperty(@NotNull String path, @NotNull PropertyType<T> type, @NotNull List<T> defaultValue) {
super(path, Collections.unmodifiableList(defaultValue));
Objects.requireNonNull(type, "type");
this.type = type;
public ListProperty(@NotNull String path, @NotNull PropertyType<E> entryType, @NotNull List<E> defaultValue) {
super(path, Collections.unmodifiableList(defaultValue), new ListPropertyType<>(entryType));
}

@Override
protected @Nullable List<T> getFromReader(@NotNull PropertyReader reader,
@NotNull ConvertErrorRecorder errorRecorder) {
List<?> list = reader.getList(getPath());

if (list != null) {
return Collections.unmodifiableList(list.stream()
.map(elem -> type.convert(elem, errorRecorder))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
}
return null;
}

@Override
public @NotNull Object toExportValue(@NotNull List<T> value) {
return value.stream()
.map(type::toExportValue)
.collect(Collectors.toList());
/**
* Constructor.
*
* @param path the path of the property
* @param type the list type
* @param defaultValue the default value of the property
*/
public ListProperty(@NotNull String path, @NotNull ListPropertyType<E> type, @NotNull List<E> defaultValue) {
super(path, Collections.unmodifiableList(defaultValue), type);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package ch.jalu.configme.properties;

import ch.jalu.configme.properties.types.SetPropertyType;
import ch.jalu.configme.properties.types.StringType;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Collections.unmodifiableSet;

/**
* Property whose value is a String set all in lowercase. The sets are immutable.
* Property whose value is a String set all in lowercase. The default value is immutable.
* The encounter order of the default value and the constructed values is preserved, unless you've provided a custom
* property type.
*/
public class LowercaseStringSetProperty extends StringSetProperty {
public class LowercaseStringSetProperty extends TypeBasedProperty<Set<String>> {

/**
* Constructor.
Expand All @@ -25,7 +27,8 @@ public class LowercaseStringSetProperty extends StringSetProperty {
* @param defaultEntries entries in the Set that is the default value
*/
public LowercaseStringSetProperty(@NotNull String path, @NotNull String @NotNull ... defaultEntries) {
super(path, toLowercaseLinkedHashSet(Arrays.stream(defaultEntries)));
super(path, toLowercaseLinkedHashSet(Arrays.stream(defaultEntries)),
new SetPropertyType<>(StringType.STRING_LOWER_CASE));
}

/**
Expand All @@ -35,13 +38,8 @@ public LowercaseStringSetProperty(@NotNull String path, @NotNull String @NotNull
* @param defaultEntries entries in the Set that is the default value
*/
public LowercaseStringSetProperty(@NotNull String path, @NotNull Collection<String> defaultEntries) {
super(path, toLowercaseLinkedHashSet(defaultEntries.stream()));
}

@Override
protected @NotNull Collector<String, ?, Set<String>> setCollector() {
Function<String, String> toLowerCaseFn = value -> String.valueOf(value).toLowerCase();
return Collectors.mapping(toLowerCaseFn, super.setCollector());
super(path, toLowercaseLinkedHashSet(defaultEntries.stream()),
new SetPropertyType<>(StringType.STRING_LOWER_CASE));
}

protected static @NotNull Set<String> toLowercaseLinkedHashSet(@NotNull Stream<String> valuesStream) {
Expand Down
Loading

0 comments on commit 4b0be9f

Please sign in to comment.