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