All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.perfectable.introspection.proxy.LazyInitialization Maven / Gradle / Ivy

There is a newer version: 5.1.0
Show newest version
package org.perfectable.introspection.proxy;

import java.lang.reflect.Method;
import java.util.Optional;
import javax.annotation.Nullable;

import com.google.errorprone.annotations.concurrent.LazyInit;

import static org.perfectable.introspection.Introspections.introspect;

/**
 * Helper class to create proxy which delegate invocation to lazily-initialized instance.
 *
 * 

Proxies are created by {@link #createProxy}. */ public final class LazyInitialization { /** * Additional interface that all proxies created by {@link #createProxy} will implement. * * @param type of actual delegation target. */ public interface Proxy { /** * Extracts delegation target. * * @return target if it was initialized, empty if proxy hasn't yet been initialized. */ Optional extractInstance(); } /** * Provider interface for proxy delegation target. * * @param type of target */ @FunctionalInterface public interface Initializer { /** * Initializes the actual target and returns it. * *

In ideal scenario this method is called once for each proxy. * * @return Delegation target for created proxy */ T initialize(); } /** * Creates a proxy that forwards invocations to lazily initialized instance. * *

On any method call on resulting proxy it will either initialize instance and cache it, or use existing * instance, and delegate the call to it, returning the result or rethrowing exception of the call. There are * two exceptions of this rule: *

    *
  • {@link Object#finalize} is always ignored when called on proxy
  • *
  • Methods from {@link Proxy} interface are treated specially and handled with separate route. They * won't necessarily initialize the proxy and won't be forwarded to the target.
  • *
* *

Proxies will have {@code resultClass} as a superclass/superinterface. Additionally, proxy class will implement * {@link Proxy} interface. This wont be reflected in the compile-time type, but it can be checked by instanceof * and it can be casted to it. * * @param resultClass class or interface that proxy has to implement. This is also a superclass/superinterface of * initialized instance * @param initializer method of initializing actual delegation target * @param type of proxy * @return proxy object */ public static T createProxy(Class resultClass, Initializer initializer) { LazyInitializationHandler handler = LazyInitializationHandler.create(initializer); return ProxyBuilder.forType(resultClass).withInterface(Proxy.class).instantiate(handler); } private static final class LazyInitializationHandler implements InvocationHandler> { private static final Method EXTRACT_INSTANCE_METHOD = introspect(Proxy.class).methods().named("extractInstance").parameters().unique(); private final Initializer initializer; @LazyInit private transient T instance; public static LazyInitializationHandler create(Initializer initializer) { return new LazyInitializationHandler<>(initializer); } private LazyInitializationHandler(Initializer initializer) { this.initializer = initializer; } @Nullable @Override public Object handle(MethodInvocation invocation) throws Throwable { return invocation.decompose(this::replaceInvocation).invoke(); } private Invocation replaceInvocation(Method method, @SuppressWarnings("unused") @Nullable T receiver, Object... arguments) { if (EXTRACT_INSTANCE_METHOD.equals(method)) { return () -> Optional.ofNullable(instance); } if (this.instance == null) { this.instance = this.initializer.initialize(); } return MethodInvocation.of(method, this.instance, arguments); } } private LazyInitialization() { // utility class } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy