Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
w.config.MapBasedMutableConfig Maven / Gradle / Ivy
/*
* Copyright 2023 Whilein
*
* 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
*
* http://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 w.config;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.val;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import w.config.mapper.BooleanMapper;
import w.config.mapper.Mapper;
import w.config.mapper.NumberMapper;
import w.config.mapper.StringMapper;
import w.config.path.ConfigPath;
import w.config.path.SimpleConfigPath;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author whilein
*/
@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true)
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class MapBasedMutableConfig implements MutableConfig, Mapper {
Map map;
@Override
public boolean equals(@Nullable Object o) {
return o == this || (o instanceof Config config && map.equals(config.asMap()));
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public @NotNull Config copyContents() {
return createObject(copyContents(map));
}
@SuppressWarnings("unchecked")
private Object copy(Object object) {
if (object instanceof Map, ?> contents) {
return copyContents((Map) contents);
} else if (object instanceof List> contents) {
return copyContents(contents);
} else {
return object;
}
}
private List copyContents(List> contents) {
val copiedList = new ArrayList<>(contents.size());
for (val element : contents) {
copiedList.add(copy(element));
}
return copiedList;
}
private Map copyContents(Map contents) {
val copiedMap = new HashMap();
for (val entry : contents.entrySet()) {
copiedMap.put(entry.getKey(), copy(entry.getValue()));
}
return copiedMap;
}
@Override
public @NotNull Mapper extends MutableConfig> configMapper() {
return this;
}
@Override
@SuppressWarnings("unchecked")
public @Nullable MutableConfig map(@Nullable Object o) {
if (o == null) {
return null;
}
if (o instanceof Map, ?>) {
return createObject((Map) o);
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public @Nullable MutableConfig mapStrict(@Nullable Object o) {
if (o == null) return null;
if (o instanceof Map, ?>) {
return createObject((Map) o);
}
throw new IllegalStateException("Cannot map " + o + " to config");
}
protected abstract MutableConfig createObject(Map map);
private T require(T value, String key) {
if (value == null) {
throw new ConfigMissingKeyException(key);
}
return value;
}
// region delegate
@Override
public @NotNull Set<@NotNull String> keySet() {
return map.keySet();
}
@Override
public @NotNull Collection<@NotNull Object> values() {
return map.values();
}
@Override
public void set(@NotNull String key, @Nullable Object object) {
map.put(key, object);
}
@Override
public void remove(@NotNull String key) {
map.remove(key);
}
@Override
public boolean contains(@NotNull String key) {
return map.containsKey(key);
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public int size() {
return map.size();
}
// endregion
// region string
@Override
public @NotNull Optional<@NotNull String> findString(@NotNull String key) {
return find(key, StringMapper.stringMapper());
}
@Override
public @NotNull String getString(@NotNull String key) {
return get(key, StringMapper.stringMapper());
}
@Override
public @Nullable String getString(@NotNull String key, @Nullable String defaultValue) {
return get(key, StringMapper.stringMapper(), defaultValue);
}
// endregion
// region boolean
@Override
public boolean getBoolean(@NotNull String key, boolean defaultValue) {
return get(key, BooleanMapper.booleanMapper(), defaultValue);
}
@Override
public boolean getBoolean(@NotNull String key) {
return get(key, BooleanMapper.booleanMapper());
}
@Override
public @NotNull Optional findBoolean(@NotNull String key) {
return find(key, BooleanMapper.booleanMapper());
}
// endregion
// region numbers
@Override
public int getInt(@NotNull String key) {
return get(key, NumberMapper.intMapper());
}
@Override
public int getInt(@NotNull String key, int defaultValue) {
return get(key, NumberMapper.intMapper(), defaultValue);
}
@Override
public @NotNull OptionalInt findInt(@NotNull String key) {
return find0(key, OptionalInt::empty, OptionalInt::of, NumberMapper.intMapper());
}
@Override
public double getDouble(@NotNull String key) {
return get(key, NumberMapper.doubleMapper());
}
@Override
public double getDouble(@NotNull String key, double defaultValue) {
return get(key, NumberMapper.doubleMapper(), defaultValue);
}
@Override
public @NotNull OptionalDouble findDouble(@NotNull String key) {
return find0(key, OptionalDouble::empty, OptionalDouble::of, NumberMapper.doubleMapper());
}
@Override
public long getLong(@NotNull String key) {
return get(key, NumberMapper.longMapper());
}
@Override
public long getLong(@NotNull String key, long defaultValue) {
return get(key, NumberMapper.longMapper(), defaultValue);
}
@Override
public @NotNull OptionalLong findLong(@NotNull String key) {
return find0(key, OptionalLong::empty, OptionalLong::of, NumberMapper.longMapper());
}
// endregion
@Override
public @NotNull Object getRaw(@NotNull String key) {
return require(map.get(key), key);
}
@Override
public @Nullable Object getRaw(@NotNull String key, @Nullable Object defaultValue) {
return map.getOrDefault(key, defaultValue);
}
@Override
public @NotNull Optional findRaw(@NotNull String key) {
return Optional.ofNullable(map.get(key));
}
@Override
public @NotNull Optional findAs(@NotNull String key, @NotNull Class type) {
return find(key, mapAs(type));
}
@Override
public @NotNull T getAs(@NotNull String key, @NotNull Class type) {
return get(key, mapAs(type));
}
@Override
public @Nullable T getAs(@NotNull String key,
@NotNull Class type,
@Nullable T def) {
return get(key, mapAs(type), def);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public @NotNull MutableConfig getObject(@NotNull String key) {
val value = map.get(key);
if (value instanceof Map mapValue) {
return createObject(mapValue);
}
throw new ConfigMissingKeyException(key);
}
@Override
public @NotNull Optional extends @NotNull MutableConfig> findObject(@NotNull String key) {
return find(key, configMapper());
}
@Override
public @NotNull T get(
@NotNull String key,
@NotNull Mapper mapper
) throws ConfigMissingKeyException {
return mapper.mapStrict(require(map.get(key), key));
}
@Override
public @Nullable T get(
@NotNull String key,
@NotNull Mapper mapper,
@Nullable T def
) {
val result = mapper.map(map.get(key));
return result == null ? def : result;
}
@Override
public @NotNull Optional find(@NotNull String key, @NotNull Mapper mapper) {
return find0(key, Optional::empty, Optional::of, mapper);
}
private T find0(
String key,
Supplier empty,
Function wrap,
Mapper mapper
) {
val result = mapper.map(map.get(key));
return result == null ? empty.get() : wrap.apply(result);
}
// region list
@Override
public @Unmodifiable @Nullable List<@NotNull Byte> getByteList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.byteMapper());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Byte> getByteList(@NotNull String key) {
return getByteList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull String> getStringList(@NotNull String key) {
return getList(key, StringMapper.stringMapper());
}
@Override
public @Unmodifiable @NotNull List extends @NotNull MutableConfig> getObjectList(@NotNull String key) {
return getList(key, configMapper(), Collections.emptyList());
}
@Override
@Contract("_, _, !null -> !null")
public @Unmodifiable @Nullable List getList(
@NotNull String key,
@NotNull Mapper mapper,
@Nullable List def
) {
val value = map.get(key);
if (value instanceof List> list) {
return list.stream()
.map(mapper::mapStrict)
.toList();
}
return def;
}
@Override
public @Unmodifiable @NotNull List getList(
@NotNull String key,
@NotNull Mapper mapper
) {
return getList(key, mapper, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Integer> getIntList(
@NotNull String key
) {
return getIntList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @Nullable List<@NotNull Integer> getIntList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.intMapper(), def);
}
@Override
public @Unmodifiable @Nullable List<@NotNull Long> getLongList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.longMapper(), def);
}
@Override
public @Unmodifiable @Nullable List<@NotNull Short> getShortList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.shortMapper());
}
@Override
public @Unmodifiable @Nullable List<@NotNull Double> getDoubleList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.doubleMapper(), def);
}
@Override
public @Unmodifiable @Nullable List<@NotNull Float> getFloatList(
@NotNull String key,
@Nullable List def
) {
return getList(key, NumberMapper.floatMapper(), def);
}
@Override
public @Unmodifiable @Nullable List<@NotNull Boolean> getBooleanList(
@NotNull String key,
@Nullable List def
) {
return getList(key, BooleanMapper.booleanMapper(), def);
}
@Override
public @Unmodifiable @NotNull List<@NotNull Long> getLongList(@NotNull String key) {
return getLongList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Short> getShortList(@NotNull String key) {
return getShortList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Double> getDoubleList(@NotNull String key) {
return getDoubleList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Float> getFloatList(@NotNull String key) {
return getFloatList(key, Collections.emptyList());
}
@Override
public @Unmodifiable @NotNull List<@NotNull Boolean> getBooleanList(@NotNull String key) {
return getBooleanList(key, Collections.emptyList());
}
@Override
public @NotNull Map<@NotNull String, @NotNull Object> asMap() {
return map;
}
@Override
public void setAll(@NotNull Config config) {
merge(map, config.asMap());
}
private void merge(List oldList, List newList) {
oldList.addAll(newList);
}
@SuppressWarnings("unchecked")
private T merge(T oldValue, T newValue) {
if (oldValue instanceof Map, ?> && newValue instanceof Map, ?>) {
merge((Map) oldValue, (Map) newValue);
return oldValue;
}
if (oldValue instanceof List> && newValue instanceof List>) {
merge((List) newValue, (List) oldValue);
return oldValue;
}
return newValue;
}
private void merge(Map oldMap, Map newMap) {
for (val entry : newMap.entrySet()) {
val key = entry.getKey();
val newValue = entry.getValue();
val oldValue = oldMap.get(key);
oldMap.put(key, merge(oldValue, newValue));
}
}
@Override
public void writeTo(@NotNull File file) {
try (val os = new FileOutputStream(file)) {
writeTo(os);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void writeTo(@NotNull Path path) {
try (val os = Files.newOutputStream(path)) {
writeTo(os);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public @NotNull MutableConfig createObject(@NotNull String key) {
val object = new LinkedHashMap();
set(key, object);
return createObject(object);
}
@Override
public @NotNull ConfigPath walk(@NotNull String path) {
return SimpleConfigPath.create(this, path);
}
}