001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate;
018
019import io.leangen.geantyref.TypeToken;
020import org.checkerframework.checker.nullness.qual.Nullable;
021import org.spongepowered.configurate.serialize.SerializationException;
022import org.spongepowered.configurate.serialize.TypeSerializer;
023import org.spongepowered.configurate.util.CheckedConsumer;
024
025import java.lang.reflect.Type;
026import java.util.List;
027import java.util.Map;
028import java.util.stream.Collector;
029
030/**
031 * Intermediate node type to reduce need for casting.
032 *
033 * <p>Any methods that return {@link ConfigurationNode} in
034 * {@link ConfigurationNode} should be overridden to return the {@link N}
035 * self-type instead.</p>
036 *
037 * @param <N> self type
038 * @since 4.0.0
039 */
040public interface ScopedConfigurationNode<N extends ScopedConfigurationNode<N>> extends ConfigurationNode {
041
042    /**
043     * Get a correctly typed instance of this node.
044     *
045     * @return the node type
046     * @since 4.0.0
047     */
048    N self();
049
050    /**
051     * {@inheritDoc}
052     */
053    @Override
054    N appendListNode();
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    N copy();
061
062    /**
063     * {@inheritDoc}
064     */
065    @Override
066    N node(Object... path);
067
068    /**
069     * {@inheritDoc}
070     */
071    @Override
072    N node(Iterable<?> path);
073
074    /**
075     * {@inheritDoc}
076     */
077    @Override
078    @Nullable N parent();
079
080    /**
081     * {@inheritDoc}
082     */
083    @Override
084    N from(ConfigurationNode other);
085
086    /**
087     * {@inheritDoc}
088     */
089    @Override
090    N mergeFrom(ConfigurationNode other);
091
092    /**
093     * {@inheritDoc}
094     */
095    @Override
096    N set(@Nullable Object value) throws SerializationException;
097
098    /**
099     * {@inheritDoc}
100     */
101    @Override
102    @SuppressWarnings({"unchecked", "rawtypes"}) // for TypeSerializer.serialize
103    default N set(Type type, @Nullable Object value) throws SerializationException {
104        if (value == null) {
105            return set(null);
106        }
107
108        final @Nullable TypeSerializer<?> serial = options().serializers().get(type);
109        if (serial != null) {
110            ((TypeSerializer) serial).serialize(type, value, self());
111        } else if (options().acceptsType(value.getClass())) {
112            raw(value); // Just write if no applicable serializer exists?
113        } else {
114            throw new SerializationException("No serializer available for type " + type);
115        }
116        return self();
117    }
118
119    @Override
120    default <V> N set(Class<V> type, @Nullable V value) throws SerializationException {
121        return set((Type) type, value);
122    }
123
124    @Override
125    default <V> N set(TypeToken<V> type, @Nullable V value) throws SerializationException {
126        return set(type.getType(), value);
127    }
128
129    @Override
130    default <V> N setList(Class<V> elementType, @Nullable List<V> items) throws SerializationException {
131        ConfigurationNode.super.setList(elementType, items);
132        return self();
133    }
134
135    @Override
136    default <V> N setList(TypeToken<V> elementType, @Nullable List<V> items) throws SerializationException {
137        ConfigurationNode.super.setList(elementType, items);
138        return self();
139    }
140
141    /**
142     * {@inheritDoc}
143     */
144    @Override
145    N raw(@Nullable Object value);
146
147    /**
148     * {@inheritDoc}
149     */
150    @Override
151    List<N> childrenList();
152
153    /**
154     * {@inheritDoc}
155     */
156    @Override
157    Map<Object, N> childrenMap();
158
159    /**
160     * {@inheritDoc}
161     */
162    @SuppressWarnings({"unchecked", "rawtypes"})
163    @Override
164    default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final TypeToken<V> valueType) {
165        return (Collector) ConfigurationNode.super.toMapCollector(valueType);
166    }
167
168    /**
169     * {@inheritDoc}
170     */
171    @SuppressWarnings({"unchecked", "rawtypes"})
172    @Override
173    default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final Class<V> valueType) {
174        return (Collector) ConfigurationNode.super.toMapCollector(valueType);
175    }
176
177    /**
178     * {@inheritDoc}
179     */
180    @SuppressWarnings({"unchecked", "rawtypes"})
181    @Override
182    default <V> Collector<V, N, N> toListCollector(final TypeToken<V> valueType) {
183        return (Collector) ConfigurationNode.super.toListCollector(valueType);
184    }
185
186    /**
187     * {@inheritDoc}
188     */
189    @SuppressWarnings({"unchecked", "rawtypes"})
190    @Override
191    default <V> Collector<V, N, N> toListCollector(final Class<V> valueType) {
192        return (Collector) ConfigurationNode.super.toListCollector(valueType);
193    }
194
195    /**
196     * Execute an action on this node. This allows performing multiple
197     * operations on a single node without having to clutter up the surrounding
198     * scope.
199     *
200     * @param <E> thrown type
201     * @param action the action to perform on this node
202     * @return this node
203     * @since 4.0.0
204     */
205    default <E extends Exception> N act(CheckedConsumer<? super N, E> action) throws E {
206        action.accept(self());
207        return self();
208    }
209
210    @Override
211    <V> N hint(RepresentationHint<V> hint, @Nullable V value);
212
213}