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

com.github.rschmitt.dynamicobject.internal.Instances Maven / Gradle / Ivy

There is a newer version: 1.7.3
Show newest version
package com.github.rschmitt.dynamicobject.internal;

import com.github.rschmitt.dynamicobject.DynamicObject;
import net.fushizen.invokedynamic.proxy.DynamicProxy;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static com.github.rschmitt.dynamicobject.internal.ClojureStuff.EmptyMap;

public class Instances {
    private static final ConcurrentMap proxyCache = new ConcurrentHashMap<>();

    public static > D newInstance(Class type) {
        return wrap(EmptyMap, type);
    }

    @SuppressWarnings("unchecked")
    public static > D wrap(Map map, Class type) {
        if (map == null)
            throw new NullPointerException("A null reference cannot be used as a DynamicObject");
        if (map instanceof DynamicObject)
            return type.cast(map);

        return createIndyProxy(map, type);
    }

    private static > D createIndyProxy(Map map, Class type) {
        ensureInitialized(type);
        try {
            Object proxy = proxyCache.computeIfAbsent(type, Instances::createProxy)
                    .constructor()
                    .invoke(map, type);
            return type.cast(proxy);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    // This is to avoid hitting JDK-8062841 in the case where 'type' has a static field of type D
    // that has not yet been initialized.
    private static synchronized > void ensureInitialized(Class c) {
        if (!proxyCache.containsKey(c))
            load(c);
    }

    private static void load(Class c) {
        try {
            Class.forName(c.getName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private static DynamicProxy createProxy(Class dynamicObjectType) {
        String[] slices = dynamicObjectType.getName().split("\\.");
        String name = slices[slices.length - 1] + "Impl";
        try {
            DynamicProxy.Builder builder = DynamicProxy.builder()
                    .withInterfaces(dynamicObjectType, CustomValidationHook.class)
                    .withSuperclass(DynamicObjectInstance.class)
                    .withInvocationHandler(new InvokeDynamicInvocationHandler(dynamicObjectType))
                    .withConstructor(Map.class, Class.class)
                    .withPackageName(dynamicObjectType.getPackage().getName())
                    .withClassName(name);
            try {
                Class iMapIterable = Class.forName("clojure.lang.IMapIterable");
                builder = builder.withInterfaces(iMapIterable);
            } catch (ClassNotFoundException ignore) {}
            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy