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.objectmapping; 018 019import io.leangen.geantyref.TypeToken; 020import org.spongepowered.configurate.ConfigurationNode; 021import org.spongepowered.configurate.objectmapping.meta.Constraint; 022import org.spongepowered.configurate.objectmapping.meta.NodeResolver; 023import org.spongepowered.configurate.objectmapping.meta.PostProcessor; 024import org.spongepowered.configurate.objectmapping.meta.Processor; 025import org.spongepowered.configurate.serialize.SerializationException; 026import org.spongepowered.configurate.serialize.TypeSerializer; 027import org.spongepowered.configurate.serialize.TypeSerializerCollection; 028import org.spongepowered.configurate.util.NamingScheme; 029 030import java.lang.annotation.Annotation; 031import java.lang.reflect.Type; 032import java.util.List; 033 034/** 035 * A mapper that converts between configuration nodes and Java objects. 036 * 037 * <p>Object mappers are created through a {@link Factory}, either the default 038 * one or one created with additional options. See that class's 039 * documentation for details.</p> 040 * 041 * <p>The object mapper can be accessed directly, through its {@link #factory()}, 042 * or through a {@link ConfigurationNode}'s 043 * {@link ConfigurationNode#get(TypeToken)} method. To use a custom factory 044 * instance through a node, a custom TypeSerializer has to be registered to the 045 * {@link TypeSerializerCollection} used 046 * by the node.</p> 047 * 048 * @param <V> mapped type 049 * @since 4.0.0 050 */ 051public interface ObjectMapper<V> { 052 053 /** 054 * Get the default object mapper factory instance. 055 * 056 * <p>This factory has the following characteristics:</p> 057 * <ul> 058 * <li>can resolve fields in empty-constructor objects and Records</li> 059 * <li>will try to resolve any field in objects</li> 060 * <li>supports {@link org.spongepowered.configurate.objectmapping.meta.NodeKey} and 061 * {@link org.spongepowered.configurate.objectmapping.meta.Setting} annotations 062 * for customizing node resolution</li> 063 * <li>uses the {@link org.spongepowered.configurate.util.NamingSchemes#LOWER_CASE_DASHED} 064 * naming scheme for other nodes</li> 065 * <li>supports unlocalized {@link org.spongepowered.configurate.objectmapping.meta.Matches}, 066 * and {@link org.spongepowered.configurate.objectmapping.meta.Required} 067 * constraints</li> 068 * <li>processes {@link org.spongepowered.configurate.objectmapping.meta.Comment} 069 * annotations</li> 070 * </ul> 071 * 072 * @return default factory 073 * @since 4.0.0 074 */ 075 static Factory factory() { 076 return ObjectMapperFactoryImpl.INSTANCE; 077 } 078 079 /** 080 * Create an empty builder. 081 * 082 * <p>This applies none of the standard formats, processors, constraints or 083 * resolvers. Unless you want to do something particularly specialized, 084 * you should probably be using {@link #factoryBuilder()}.</p> 085 * 086 * @return new empty builder 087 * @since 4.0.0 088 */ 089 static Factory.Builder emptyFactoryBuilder() { 090 return new ObjectMapperFactoryImpl.Builder(); 091 } 092 093 /** 094 * Create a builder populated with default settings. 095 * 096 * <p>This builder is prepared to allow overriding any of the default 097 * object mapper features.</p> 098 * 099 * @return new builder 100 * @see #factory() for a description of the default settings 101 * @since 4.0.0 102 */ 103 static Factory.Builder factoryBuilder() { 104 return ObjectMapperFactoryImpl.defaultBuilder(); 105 } 106 107 /** 108 * Create a new object instance. 109 * 110 * @param source object source 111 * @return new instance 112 * @throws SerializationException if any invalid data is present. Loading is 113 * done in stages, so any deserialization errors will occur before 114 * anything is written to objects. 115 * @since 4.0.0 116 */ 117 V load(ConfigurationNode source) throws SerializationException; 118 119 /** 120 * Write data from the provided object to the target. 121 * 122 * @param value value type 123 * @param target destination 124 * @throws SerializationException if unable to fully save 125 * @since 4.0.0 126 */ 127 void save(V value, ConfigurationNode target) throws SerializationException; 128 129 /** 130 * Get the parameters that will be handled by this mapper. 131 * 132 * @return immutable list of fields 133 * @since 4.0.0 134 */ 135 List<? extends FieldData<?, V>> fields(); 136 137 /** 138 * The generic type of object that this mapper instance handles. 139 * 140 * @return object type 141 * @since 4.0.0 142 */ 143 Type mappedType(); 144 145 /** 146 * Get whether or not this mapper is capable of creating new instances of 147 * its mapped type. 148 * 149 * <p>If this returns {@code false}, {@link #load(ConfigurationNode)} will 150 * always fail.</p> 151 * 152 * @return if the mapped type can be instantiated. 153 * @since 4.0.0 154 */ 155 boolean canCreateInstances(); 156 157 /** 158 * An object mapper capable of loading data into an existing object. 159 * 160 * @param <V> value type 161 * @since 4.0.0 162 */ 163 interface Mutable<V> extends ObjectMapper<V> { 164 165 /** 166 * Load data from {@code node} into an existing instance. 167 * 168 * @param value existing instance 169 * @param node node to load from 170 * @throws SerializationException if unable to deserialize data 171 * @since 4.0.0 172 */ 173 void load(V value, ConfigurationNode node) throws SerializationException; 174 175 } 176 177 /** 178 * Provider for object mappers. 179 * 180 * @since 4.0.0 181 */ 182 interface Factory { 183 184 /** 185 * Get an object mapper for the provided type. 186 * 187 * <p>The provided type cannot be a <em>raw type</em>.</p> 188 * 189 * @param type token holding the mapped type 190 * @param <V> mapped type 191 * @return a mapper for the provided type 192 * @throws SerializationException if the type does not correspond to a 193 * mappable object 194 * @since 4.0.0 195 */ 196 @SuppressWarnings("unchecked") 197 default <V> ObjectMapper<V> get(final TypeToken<V> type) throws SerializationException { 198 return (ObjectMapper<V>) get(type.getType()); 199 } 200 201 /** 202 * Get an object mapper for the unparameterized type {@code clazz}. 203 * 204 * <p>The provided type cannot be a <em>raw type</em>.</p> 205 * 206 * @param clazz class of the mapped type 207 * @param <V> mapped type 208 * @return a mapper for the provided type 209 * @throws SerializationException if the type does not correspond to a 210 * mappable object 211 * @since 4.0.0 212 */ 213 @SuppressWarnings("unchecked") 214 default <V> ObjectMapper<V> get(final Class<V> clazz) throws SerializationException { 215 return (ObjectMapper<V>) get((Type) clazz); 216 } 217 218 /** 219 * Get the object mapper for the provided type. 220 * 221 * <p>The provided type cannot be a <em>raw type</em>.</p> 222 * 223 * @param type object type. 224 * @return a mapper for the provided type 225 * @throws SerializationException if the type does not correspond to a 226 * mappable object 227 * @since 4.0.0 228 */ 229 ObjectMapper<?> get(Type type) throws SerializationException; 230 231 /** 232 * Creates a {@link TypeSerializer} that uses this factory. 233 * 234 * <p>The serializer will accept any object type that could otherwise be 235 * handled by this factory. To match a standard configuration, 236 * register this serializer with {@link TypeSerializerCollection.Builder#registerAnnotatedObjects(Factory)} 237 * to enforce the presence of {@link ConfigSerializable} annotations.</p> 238 * 239 * @return a type serializer 240 * @since 4.0.0 241 */ 242 TypeSerializer<Object> asTypeSerializer(); 243 244 /** 245 * A builder for a configured factory producing object mappers. 246 * 247 * <p>In general, with multiple applicable resolvers, the one registered 248 * last will take priority.</p> 249 * 250 * @since 4.0.0 251 */ 252 interface Builder { 253 254 /** 255 * Set the naming scheme to use as a default for field names. 256 * 257 * <p>This can be overridden by other 258 * {@link NodeResolver NodeResolvers} for specific nodes.</p> 259 * 260 * @param scheme naming scheme 261 * @return this builder 262 * @since 4.0.0 263 */ 264 Builder defaultNamingScheme(NamingScheme scheme); 265 266 /** 267 * Add a resolver that will locate a node for a field. 268 * 269 * @param resolver the resolver 270 * @return this builder 271 * @since 4.0.0 272 */ 273 Builder addNodeResolver(NodeResolver.Factory resolver); 274 275 /** 276 * Add a discoverer for a type of object. 277 * 278 * <p>Field discoverers will be tried in order until one can 279 * produce the appropriate metadata.</p> 280 * 281 * @param discoverer field discoverer 282 * @return this builder 283 * @since 4.0.0 284 */ 285 Builder addDiscoverer(FieldDiscoverer<?> discoverer); 286 287 /** 288 * Register a {@link Processor} that will process fields after write. 289 * 290 * <p>Processors registered without a specific data type should be 291 * able to operate on any value type.</p> 292 * 293 * @param definition annotation providing data 294 * @param factory factory for callback function 295 * @param <A> annotation type 296 * @return this builder 297 * @since 4.0.0 298 */ 299 default <A extends Annotation> Builder addProcessor(final Class<A> definition, final Processor.Factory<A, Object> factory) { 300 return addProcessor(definition, Object.class, factory); 301 } 302 303 /** 304 * Register a {@link Processor} that will process fields after write. 305 * 306 * <p>All value types will be tested against types normalized to 307 * their boxed variants.</p> 308 * 309 * @param definition annotation providing data 310 * @param valueType value types the processor will handle 311 * @param factory factory for callback function 312 * @param <A> annotation type 313 * @param <T> data type 314 * @return this builder 315 * @since 4.0.0 316 */ 317 <A extends Annotation, T> Builder addProcessor(Class<A> definition, Class<T> valueType, Processor.Factory<A, T> factory); 318 319 /** 320 * Register a {@link Constraint} that will be used to validate fields. 321 * 322 * <p>Constraints registered without a specific data type will be 323 * able to operate on any value type.</p> 324 * 325 * @param definition annotations providing data 326 * @param factory factory for callback function 327 * @param <A> annotation type 328 * @return this builder 329 * @since 4.0.0 330 */ 331 default <A extends Annotation> Builder addConstraint(final Class<A> definition, final Constraint.Factory<A, Object> factory) { 332 return addConstraint(definition, Object.class, factory); 333 } 334 335 /** 336 * Register a {@link Constraint} that will be used to validate fields. 337 * 338 * <p>All value types will be tested against types normalized to 339 * their boxed variants.</p> 340 * 341 * @param definition annotations providing data 342 * @param valueType value types the processor will handle 343 * @param factory factory for callback function 344 * @param <A> annotation type 345 * @param <T> data type 346 * @return this builder 347 * @since 4.0.0 348 */ 349 <A extends Annotation, T> Builder addConstraint(Class<A> definition, Class<T> valueType, Constraint.Factory<A, T> factory); 350 351 /** 352 * Register an object post-processor with this object mapper. 353 * 354 * <p>All post-processors will be called, even if one 355 * throws an exception.</p> 356 * 357 * @param factory the factory optionally producing a 358 * post processor function 359 * @return this builder 360 * @since 4.2.0 361 */ 362 Builder addPostProcessor(PostProcessor.Factory factory); 363 364 /** 365 * Create a new factory using the current configuration. 366 * 367 * @return new factory instance 368 * @since 4.0.0 369 */ 370 Factory build(); 371 372 } 373 374 } 375 376}