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.spongepowered.configurate.serialize.SerializationException; 021import org.spongepowered.configurate.util.CheckedConsumer; 022 023import java.util.Map; 024import java.util.stream.Collector; 025 026/** 027 * Something that can create a customized node. 028 * 029 * @since 4.0.0 030 */ 031@FunctionalInterface 032public interface ConfigurationNodeFactory<N extends ConfigurationNode> { 033 034 /** 035 * Default options for the types of nodes created by this factory. 036 * 037 * <p>All values must match what a created node will see, but some values 038 * may be determined by this factory to be non user-modifiable. These should 039 * be documented for any factory implementation. 040 * 041 * @return default options 042 * @since 4.0.0 043 */ 044 default ConfigurationOptions defaultOptions() { 045 return ConfigurationOptions.defaults(); 046 } 047 048 /** 049 * Create an empty node with the provided options. 050 * 051 * <p>Node options may be overridden if the factory enforces specific 052 * requirements on options. 053 * 054 * @param options node options 055 * @return newly created empty node 056 * @since 4.0.0 057 */ 058 N createNode(ConfigurationOptions options); 059 060 /** 061 * Create a new node with default options. 062 * 063 * @return newly created empty node 064 * @since 4.0.0 065 */ 066 default N createNode() { 067 return createNode(defaultOptions()); 068 } 069 070 /** 071 * Create a new node with default options and initialize it with the 072 * provided action. 073 * 074 * @param <E> thrown type 075 * @param action action to initialize node with 076 * @return newly created empty node 077 * @throws E when thrown from inner action 078 * @since 4.0.0 079 */ 080 default <E extends Exception> N createNode(final CheckedConsumer<N, E> action) throws E { 081 final N node = createNode(); 082 action.accept(node); 083 return node; 084 } 085 086 /** 087 * Create a new node with the provided options and initialize it with the 088 * provided action. 089 * 090 * <p>Node options may be overridden if the factory enforces specific 091 * requirements on options. 092 * 093 * @param <E> thrown type 094 * @param options node options 095 * @param action action to initialize node with 096 * @return newly created empty node 097 * @throws E when thrown from inner action 098 * @since 4.0.0 099 */ 100 default <E extends Exception> N createNode(final ConfigurationOptions options, final CheckedConsumer<N, E> action) throws E { 101 final N node = createNode(options); 102 action.accept(node); 103 return node; 104 } 105 106 /** 107 * Create a collector that appends values to a newly created node as 108 * map children. 109 * 110 * <p>This collector does not accept values in parallel.</p> 111 * 112 * @param valueType marker for value type 113 * @param <V> value type 114 * @return a new collector 115 * @since 4.0.0 116 */ 117 default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final TypeToken<V> valueType) { 118 return Collector.of(this::createNode, (node, entry) -> { 119 try { 120 node.node(entry.getKey()).set(valueType, entry.getValue()); 121 } catch (SerializationException e) { 122 throw new IllegalArgumentException(e); 123 } 124 }, (a, b) -> { 125 a.mergeFrom(b); 126 return a; 127 }); 128 } 129 130 /** 131 * Create a collector that appends values to a newly created node as 132 * map children. 133 * 134 * <p>This collector does not accept values in parallel.</p> 135 * 136 * @param valueType marker for value type 137 * @param <V> value type 138 * @return a new collector 139 * @since 4.0.0 140 */ 141 default <V> Collector<Map.Entry<?, V>, N, N> toMapCollector(final Class<V> valueType) { 142 return Collector.of(this::createNode, (node, entry) -> { 143 try { 144 node.node(entry.getKey()).set(valueType, entry.getValue()); 145 } catch (SerializationException e) { 146 throw new IllegalArgumentException(e); 147 } 148 }, (a, b) -> { 149 a.mergeFrom(b); 150 return a; 151 }); 152 } 153 154 /** 155 * Create a collector that appends values to a newly created node as 156 * list children. 157 * 158 * <p>This collector does not accept values in parallel.</p> 159 * 160 * @param valueType marker for value type 161 * @param <V> value type 162 * @return a new collector 163 * @since 4.0.0 164 */ 165 default <V> Collector<V, N, N> toListCollector(final TypeToken<V> valueType) { 166 return Collector.of(this::createNode, (node, value) -> { 167 try { 168 node.appendListNode().set(valueType, value); 169 } catch (SerializationException e) { 170 throw new IllegalArgumentException(e); 171 } 172 }, (a, b) -> { 173 a.mergeFrom(b); 174 return a; 175 }); 176 } 177 178 /** 179 * Create a collector that appends values to a newly created node as 180 * list children. 181 * 182 * <p>This collector does not accept values in parallel.</p> 183 * 184 * @param valueType marker for value type 185 * @param <V> value type 186 * @return a new collector 187 * @since 4.0.0 188 */ 189 default <V> Collector<V, N, N> toListCollector(final Class<V> valueType) { 190 return Collector.of(this::createNode, (node, value) -> { 191 try { 192 node.appendListNode().set(valueType, value); 193 } catch (SerializationException e) { 194 throw new IllegalArgumentException(e); 195 } 196 }, (a, b) -> { 197 a.mergeFrom(b); 198 return a; 199 }); 200 } 201 202}