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 static java.util.Objects.requireNonNull; 020 021import org.checkerframework.checker.nullness.qual.Nullable; 022import org.spongepowered.configurate.serialize.SerializationException; 023import org.spongepowered.configurate.util.CheckedFunction; 024 025import java.lang.reflect.AnnotatedElement; 026import java.lang.reflect.AnnotatedType; 027import java.util.function.Supplier; 028 029/** 030 * Interface that gathers metadata from classes. 031 * 032 * <p>Any type of data object can be added this way.</p> 033 * 034 * @param <I> intermediate data type 035 * @since 4.0.0 036 */ 037public interface FieldDiscoverer<I> { 038 039 /** 040 * Create a new field discoverer that will handle record classes. 041 * 042 * <p>This discoverer will use the record's canonical constructor to create 043 * new instances, passing {@code null} for any missing parameters. The 044 * accessor methods for each record component will be used to read 045 * values from the record.</p> 046 * 047 * @implNote To avoid requiring preview features to run on Java 14 and 15, 048 * the record discoverer accesses methods reflectively, and can safely 049 * be created and applied to object mappers running on any Java version. 050 * Continued support of preview features once they have been released in 051 * a stable Java version is not guaranteed. 052 * 053 * @return new discoverer 054 * @since 4.0.0 055 */ 056 static FieldDiscoverer<?> record() { 057 return RecordFieldDiscoverer.INSTANCE; 058 } 059 060 /** 061 * Create a new discoverer for object instance fields. 062 * 063 * <p>This discoverer will process any non-static and non-transient field 064 * in the object. Modifying {@code final} fields is unsupported and may stop 065 * working with newer Java versions.</p> 066 * 067 * @param instanceFactory a factory for instance providers 068 * @return new discoverer 069 * @since 4.0.0 070 */ 071 static FieldDiscoverer<?> object(final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory) { 072 return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), null, false); 073 } 074 075 /** 076 * Create a new discoverer for object instance fields. 077 * 078 * <p>This discoverer will process any non-static and non-transient field 079 * in the object. Modifying {@code final} fields is unsupported and may stop 080 * working with newer Java versions.</p> 081 * 082 * @param instanceFactory a factory for instance providers 083 * @param instanceUnavailableErrorMessage a message that will be part of the 084 * exception thrown when trying to create instances for an 085 * unsupported type 086 * @return new discoverer 087 * @since 4.1.0 088 */ 089 static FieldDiscoverer<?> object(final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory, 090 final String instanceUnavailableErrorMessage) { 091 requireNonNull(instanceUnavailableErrorMessage, "instanceUnavailableErrorMessage"); 092 return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), instanceUnavailableErrorMessage, false); 093 } 094 095 /** 096 * Create a new discoverer for object instance fields. 097 * 098 * <p>This discoverer will process any non-static and non-transient field 099 * in the object. Modifying {@code final} fields is unsupported and may stop 100 * working with newer Java versions.</p> 101 * 102 * <p>This discoverer will only match objects that it can create an instance 103 * of (i. e. where {@code instanceFactory} returns a 104 * non-{@code null} supplier).</p> 105 * 106 * @param instanceFactory a factory for instance providers 107 * @return new discoverer 108 * @since 4.2.0 109 */ 110 static FieldDiscoverer<?> instantiableObject( 111 final CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> instanceFactory 112 ) { 113 return new ObjectFieldDiscoverer(requireNonNull(instanceFactory, "instanceFactory"), null, true); 114 } 115 116 /** 117 * Create a new discoverer for object instance fields. 118 * 119 * <p>Only objects with empty constructors can be created.</p> 120 * 121 * @return new discoverer 122 * @see #object(CheckedFunction) for more details on which fields will 123 * be discovered. 124 * @since 4.0.0 125 */ 126 static FieldDiscoverer<?> emptyConstructorObject() { 127 return ObjectFieldDiscoverer.EMPTY_CONSTRUCTOR_INSTANCE; 128 } 129 130 /** 131 * Inspect the {@code target} type for fields to be supplied to 132 * the {@code collector}. 133 * 134 * <p>If the target type is handleable, a non-null value must be returned. 135 * Fields can only be collected from one source at the moment, so if the 136 * instance factory is null any discovered fields will be discarded.</p> 137 * 138 * @param target type to inspect 139 * @param collector collector for discovered fields. 140 * @param <V> object type 141 * @return a factory for handling the construction of object instances, or 142 * {@code null} if {@code target} is not of a handleable type. 143 * @throws SerializationException if any fields have invalid data 144 * @since 4.0.0 145 */ 146 <V> @Nullable InstanceFactory<I> discover(AnnotatedType target, FieldCollector<I, V> collector) throws SerializationException; 147 148 /** 149 * A handler that controls the deserialization process for an object. 150 * 151 * @param <I> intermediate type 152 * @since 4.0.0 153 */ 154 interface InstanceFactory<I> { 155 156 /** 157 * Return a new instance of the intermediary type to be populated. 158 * 159 * @return new intermediate container 160 * @since 4.0.0 161 */ 162 I begin(); 163 164 /** 165 * Return a finalized object based on the provided intermediate. 166 * 167 * @param intermediate intermediate container to hold values 168 * @return final value 169 * @throws SerializationException if unable to construct a 170 * @since 4.0.0 171 */ 172 Object complete(I intermediate) throws SerializationException; 173 174 /** 175 * Get whether or not new object instances can be created. 176 * 177 * @return new instance creation 178 * @since 4.0.0 179 */ 180 boolean canCreateInstances(); 181 } 182 183 /** 184 * A handler for working with mutable objects in the object mapper. 185 * 186 * @param <I> intermediate type 187 * @since 4.0.0 188 */ 189 interface MutableInstanceFactory<I> extends InstanceFactory<I> { 190 191 /** 192 * Apply the intermediate data to an existing object. 193 * 194 * @param instance instance to write to 195 * @param intermediate intermediate container 196 * @throws SerializationException if unable to apply info 197 * @since 4.0.0 198 */ 199 void complete(Object instance, I intermediate) throws SerializationException; 200 } 201 202 /** 203 * A collector for the necessary metadata for fields. 204 * 205 * @param <I> intermediate type 206 * @param <V> container type 207 * @since 4.0.0 208 */ 209 @FunctionalInterface 210 interface FieldCollector<I, V> { 211 212 /** 213 * Accept metadata that defines a specific field. 214 * 215 * @param name name 216 * @param type declared field type, as resolved as possible 217 * @param annotations combined element containing all annotations 218 * applicable to the field 219 * @param deserializer a function to populate the intermediate state 220 * with a single deserialized field value. 221 * @param serializer a function to extract a value from a completed 222 * object instance. 223 * @since 4.0.0 224 */ 225 void accept(String name, AnnotatedType type, AnnotatedElement annotations, FieldData.Deserializer<I> deserializer, 226 CheckedFunction<V, @Nullable Object, Exception> serializer); 227 } 228 229}