ObjectBuilderProvider.java
package space.sunqian.common.object.data;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import space.sunqian.annotations.RetainedParam;
import space.sunqian.annotations.ThreadSafe;
import space.sunqian.common.collect.ListKit;
import space.sunqian.common.invoke.Invocable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Provider for getting {@link ObjectBuilder}.
* <p>
* It contains and uses a list of {@link Handler}s to sequentially attempt get the instance of {@link ObjectBuilder}.
* The thread safety of the methods in this interface is determined by its dependent {@link BuilderCache}. By default,
* they are thread-safe.
*/
public interface ObjectBuilderProvider {
/**
* Returns the default {@link ObjectBuilderProvider}.
* <p>
* The default {@link ObjectBuilderProvider} will cache the {@link ObjectBuilder}s, which are created by its
* handlers, into a cache based on a {@link ConcurrentHashMap} (so it is thread-safe). And it has only one handler,
* which uses {@link Invocable#of(Constructor)} with the empty constructor of the target class (if it has) to
* implement {@link ObjectBuilder#newBuilder()} and directly returns the builder object itself on
* {@link ObjectBuilder#build(Object)}.
*
* @return the default {@link ObjectBuilderProvider}
*/
static @Nonnull ObjectBuilderProvider defaultProvider() {
return ObjectBuilderProviderImpl.DEFAULT;
}
/**
* Creates and returns a new {@link ObjectBuilderProvider} with the given handlers. The returned
* {@link ObjectBuilderProvider} has a {@link BuilderCache} based on a {@link ConcurrentHashMap}, so it is
* thread-safe.
*
* @param handlers the given handlers
* @return a new {@link ObjectBuilderProvider} with the given builder cache and handlers
*/
static @Nonnull ObjectBuilderProvider newProvider(
@Nonnull @RetainedParam Handler @Nonnull ... handlers
) {
return newProvider(newBuilderCache(new ConcurrentHashMap<>()), ListKit.list(handlers));
}
/**
* Creates and returns a new {@link ObjectBuilderProvider} with the given builder cache and handlers.
*
* @param cache the given builder cache
* @param handlers the given handlers
* @return a new {@link ObjectBuilderProvider} with the given builder cache and handlers
*/
static @Nonnull ObjectBuilderProvider newProvider(
@Nonnull BuilderCache cache,
@Nonnull @RetainedParam Handler @Nonnull ... handlers
) {
return newProvider(cache, ListKit.list(handlers));
}
/**
* Creates and returns a new {@link ObjectBuilderProvider} with the given builder cache and handlers.
*
* @param cache the given builder cache
* @param handlers the given handlers
* @return a new {@link ObjectBuilderProvider} with the given builder cache and handlers
*/
static @Nonnull ObjectBuilderProvider newProvider(
@Nonnull BuilderCache cache,
@Nonnull @RetainedParam List<@Nonnull Handler> handlers
) {
return new ObjectBuilderProviderImpl(cache, handlers);
}
/**
* Returns a new builder cache with the given map. The thread safety is determined by the given map.
*
* @param map the given map
* @return a new builder cache with the given map
*/
static @Nonnull BuilderCache newBuilderCache(
@Nonnull Map<@Nonnull Type, @Nonnull ObjectBuilder> map
) {
return new ObjectBuilderProviderImpl.BuilderCacheImpl(map);
}
/**
* Returns an instance of {@link ObjectBuilder}, or {@code null} if the target type is unsupported.
*
* @param target the target type
* @return an instance of {@link ObjectBuilder}, or {@code null} if the target type is unsupported
* @throws DataObjectException if an error occurs
*/
@Nullable
ObjectBuilder builder(@Nonnull Type target) throws DataObjectException;
/**
* Returns all handlers of this builder provider.
*
* @return all handlers of this builder provider
*/
@Nonnull
List<@Nonnull Handler> handlers();
/**
* Returns a new {@link ObjectBuilderProvider} of which handler list consists of the given handler as the first
* element, followed by {@link #handlers()} of the current builder provider.
* <p>
* The builder cache will be shared with the current builder provider.
*
* @param handler the given handler
* @return a new {@link ObjectBuilderProvider} of which handler list consists of the given handler as the first
* element, followed by {@link #handlers()} of the current builder provider
*/
@Nonnull
ObjectBuilderProvider withFirstHandler(@Nonnull Handler handler);
/**
* Returns a new {@link ObjectBuilderProvider} of which handler list consists of {@link #handlers()} of the current
* builder provider, followed by the given handler as the last element.
* <p>
* The builder cache will be shared with the current builder provider.
*
* @param handler the given handler
* @return a {@link ObjectBuilderProvider} of which handler list consists of {@link #handlers()} of the current
* builder provider, followed by the given handler as the last element
*/
@Nonnull
ObjectBuilderProvider withLastHandler(@Nonnull Handler handler);
/**
* Returns this builder provider as a {@link Handler}.
*
* @return this builder provider as a {@link Handler}
*/
@Nonnull
Handler asHandler();
/**
* Cache of {@link ObjectBuilder} for an instance of {@link ObjectBuilderProvider}.
*/
interface BuilderCache {
/**
* Returns the {@link ObjectBuilder} for the target type. If the {@link ObjectBuilder} is not cached, it will be
* loaded by the given loader. The semantics of this method are the same as
* {@link Map#computeIfAbsent(Object, Function)}.
*
* @param target the target type
* @param loader the loader for loading new {@link ObjectBuilder}
* @return the {@link ObjectBuilder} for the target type, or {@code null} if no mapping and no loading for the
* target type
* @throws DataObjectException if an error occurs during loading
*/
@Nullable
ObjectBuilder get(
@Nonnull Type target,
@Nonnull Function<? super @Nonnull Type, ? extends @Nullable ObjectBuilder> loader
) throws DataObjectException;
}
/**
* Handler for {@link ObjectBuilderProvider}, provides the specific builder generating logic.
*
* @author sunqian
*/
@ThreadSafe
interface Handler {
/**
* Creates and returns a new {@link ObjectBuilder}, or {@code null} if the target type is unsupported.
*
* @param target the target type
* @return a new {@link ObjectBuilder}, or {@code null} if the target type is unsupported
* @throws Exception if an error occurs
*/
@Nullable
ObjectBuilder newBuilder(@Nonnull Type target) throws Exception;
}
}