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.GenericTypeReflector; 020import io.leangen.geantyref.TypeToken; 021import org.checkerframework.checker.nullness.qual.Nullable; 022import org.spongepowered.configurate.serialize.SerializationException; 023import org.spongepowered.configurate.serialize.TypeSerializer; 024import org.spongepowered.configurate.util.CheckedConsumer; 025 026import java.lang.reflect.Type; 027import java.util.List; 028import java.util.Map; 029import java.util.stream.Collector; 030 031/** 032 * Intermediate node type to reduce need for casting. 033 * 034 * <p>Any methods that return {@link ConfigurationNode} in 035 * {@link ConfigurationNode} should be overridden to return the {@link N} 036 * self-type instead.</p> 037 * 038 * @param <N> self type 039 * @since 4.0.0 040 */ 041public interface ScopedConfigurationNode<N extends ScopedConfigurationNode<N>> extends ConfigurationNode { 042 043 /** 044 * Get a correctly typed instance of this node. 045 * 046 * @return the node type 047 * @since 4.0.0 048 */ 049 N self(); 050 051 /** 052 * {@inheritDoc} 053 */ 054 @Override 055 N appendListNode(); 056 057 /** 058 * {@inheritDoc} 059 */ 060 @Override 061 N copy(); 062 063 /** 064 * {@inheritDoc} 065 */ 066 @Override 067 N node(Object... path); 068 069 /** 070 * {@inheritDoc} 071 */ 072 @Override 073 N node(Iterable<?> path); 074 075 /** 076 * {@inheritDoc} 077 */ 078 @Override 079 @Nullable N parent(); 080 081 /** 082 * {@inheritDoc} 083 */ 084 @Override 085 N from(ConfigurationNode other); 086 087 /** 088 * {@inheritDoc} 089 */ 090 @Override 091 N mergeFrom(ConfigurationNode other); 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 N set(@Nullable Object value) throws SerializationException; 098 099 /** 100 * {@inheritDoc} 101 */ 102 @Override 103 @SuppressWarnings({"unchecked", "rawtypes"}) // for TypeSerializer.serialize 104 default N set(Type type, @Nullable Object value) throws SerializationException { 105 if (value == null) { 106 return set(null); 107 } 108 final Class<?> erasedType = GenericTypeReflector.erase(type); 109 if (!erasedType.isInstance(value)) { 110 throw new SerializationException(this, type, "Got a value of unexpected type " 111 + value.getClass().getName() + ", when the value should be an instance of " + erasedType.getSimpleName()); 112 } 113 114 final @Nullable TypeSerializer<?> serial = options().serializers().get(type); 115 if (serial != null) { 116 ((TypeSerializer) serial).serialize(type, value, self()); 117 } else if (options().acceptsType(value.getClass())) { 118 raw(value); // Just write if no applicable serializer exists? 119 } else { 120 throw new SerializationException(this, type, "No serializer available for type " + type); 121 } 122 return self(); 123 } 124 125 @Override 126 default <V> N set(Class<V> type, @Nullable V value) throws SerializationException { 127 return set((Type) type, value); 128 } 129 130 @Override 131 default <V> N set(TypeToken<V> type, @Nullable V value) throws SerializationException { 132 return set(type.getType(), value); 133 } 134 135 @Override 136 default <V> N setList(Class<V> elementType, @Nullable List<V> items) throws SerializationException { 137 ConfigurationNode.super.setList(elementType, items); 138 return self(); 139 } 140 141 @Override 142 default <V> N setList(TypeToken<V> elementType, @Nullable List<V> items) throws SerializationException { 143 ConfigurationNode.super.setList(elementType, items); 144 return self(); 145 } 146 147 /** 148 * {@inheritDoc} 149 */ 150 @Override 151 N raw(@Nullable Object value); 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 List<N> childrenList(); 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override 163 Map<Object, N> childrenMap(); 164 165 /** 166 * {@inheritDoc} 167 */ 168 @SuppressWarnings({"unchecked", "rawtypes"}) 169 @Override 170 default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final TypeToken<V> valueType) { 171 return (Collector) ConfigurationNode.super.toMapCollector(valueType); 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @SuppressWarnings({"unchecked", "rawtypes"}) 178 @Override 179 default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final Class<V> valueType) { 180 return (Collector) ConfigurationNode.super.toMapCollector(valueType); 181 } 182 183 /** 184 * {@inheritDoc} 185 */ 186 @SuppressWarnings({"unchecked", "rawtypes"}) 187 @Override 188 default <V> Collector<V, N, N> toListCollector(final TypeToken<V> valueType) { 189 return (Collector) ConfigurationNode.super.toListCollector(valueType); 190 } 191 192 /** 193 * {@inheritDoc} 194 */ 195 @SuppressWarnings({"unchecked", "rawtypes"}) 196 @Override 197 default <V> Collector<V, N, N> toListCollector(final Class<V> valueType) { 198 return (Collector) ConfigurationNode.super.toListCollector(valueType); 199 } 200 201 /** 202 * Execute an action on this node. This allows performing multiple 203 * operations on a single node without having to clutter up the surrounding 204 * scope. 205 * 206 * @param <E> thrown type 207 * @param action the action to perform on this node 208 * @return this node 209 * @since 4.0.0 210 */ 211 default <E extends Exception> N act(CheckedConsumer<? super N, E> action) throws E { 212 action.accept(self()); 213 return self(); 214 } 215 216 @Override 217 <V> N hint(RepresentationHint<V> hint, @Nullable V value); 218 219}