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); 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); 093 } 094 095 /** 096 * Create a new discoverer for object instance fields. 097 * 098 * <p>Only objects with empty constructors can be created.</p> 099 * 100 * @return new discoverer 101 * @see #object(CheckedFunction) for more details on which fields will 102 * be discovered. 103 * @since 4.0.0 104 */ 105 static FieldDiscoverer<?> emptyConstructorObject() { 106 return ObjectFieldDiscoverer.EMPTY_CONSTRUCTOR_INSTANCE; 107 } 108 109 /** 110 * Inspect the {@code target} type for fields to be supplied to 111 * the {@code collector}. 112 * 113 * <p>If the target type is handleable, a non-null value must be returned. 114 * Fields can only be collected from one source at the moment, so if the 115 * instance factory is null any discovered fields will be discarded.</p> 116 * 117 * @param target type to inspect 118 * @param collector collector for discovered fields. 119 * @param <V> object type 120 * @return a factory for handling the construction of object instances, or 121 * {@code null} if {@code target} is not of a handleable type. 122 * @throws SerializationException if any fields have invalid data 123 * @since 4.0.0 124 */ 125 <V> @Nullable InstanceFactory<I> discover(AnnotatedType target, FieldCollector<I, V> collector) throws SerializationException; 126 127 /** 128 * A handler that controls the deserialization process for an object. 129 * 130 * @param <I> intermediate type 131 * @since 4.0.0 132 */ 133 interface InstanceFactory<I> { 134 135 /** 136 * Return a new instance of the intermediary type to be populated. 137 * 138 * @return new intermediate container 139 * @since 4.0.0 140 */ 141 I begin(); 142 143 /** 144 * Return a finalized object based on the provided intermediate. 145 * 146 * @param intermediate intermediate container to hold values 147 * @return final value 148 * @throws SerializationException if unable to construct a 149 * @since 4.0.0 150 */ 151 Object complete(I intermediate) throws SerializationException; 152 153 /** 154 * Get whether or not new object instances can be created. 155 * 156 * @return new instance creation 157 * @since 4.0.0 158 */ 159 boolean canCreateInstances(); 160 } 161 162 /** 163 * A handler for working with mutable objects in the object mapper. 164 * 165 * @param <I> intermediate type 166 * @since 4.0.0 167 */ 168 interface MutableInstanceFactory<I> extends InstanceFactory<I> { 169 170 /** 171 * Apply the intermediate data to an existing object. 172 * 173 * @param instance instance to write to 174 * @param intermediate intermediate container 175 * @throws SerializationException if unable to apply info 176 * @since 4.0.0 177 */ 178 void complete(Object instance, I intermediate) throws SerializationException; 179 } 180 181 /** 182 * A collector for the necessary metadata for fields. 183 * 184 * @param <I> intermediate type 185 * @param <V> container type 186 * @since 4.0.0 187 */ 188 @FunctionalInterface 189 interface FieldCollector<I, V> { 190 191 /** 192 * Accept metadata that defines a specific field. 193 * 194 * @param name name 195 * @param type declared field type, as resolved as possible 196 * @param annotations combined element containing all annotations 197 * applicable to the field 198 * @param deserializer a function to populate the intermediate state 199 * with a single deserialized field value. 200 * @param serializer a function to extract a value from a completed 201 * object instance. 202 * @since 4.0.0 203 */ 204 void accept(String name, AnnotatedType type, AnnotatedElement annotations, FieldData.Deserializer<I> deserializer, 205 CheckedFunction<V, @Nullable Object, Exception> serializer); 206 } 207 208}