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

org.eclipse.yasson.internal.components.BeanManagerInstanceCreator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

package org.eclipse.yasson.internal.components;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.InjectionTarget;
import jakarta.json.bind.JsonbException;

import org.eclipse.yasson.internal.JsonBinding;
import org.eclipse.yasson.internal.properties.MessageKeys;
import org.eclipse.yasson.internal.properties.Messages;
import org.eclipse.yasson.spi.JsonbComponentInstanceCreator;

/**
 * CDI instance manager.
 * Instances are created and stored per instance of {@link JsonBinding}.
 * Calling close on JsonBinding, cleans up Jsonb CDI instances and in case of "dependant" scope its dependencies.
 *
 * CDI API dependency is optional, this class is never referenced / loaded if CDI API is not resolvable.
 */
public class BeanManagerInstanceCreator implements JsonbComponentInstanceCreator {

    private final BeanManager beanManager;

    private final ConcurrentMap, CDIManagedBean> injectionTargets = new ConcurrentHashMap<>();

    /**
     * Creates a new instance.
     *
     * @param beanManager Bean manager.
     */
    public BeanManagerInstanceCreator(Object beanManager) {
        if (!(beanManager instanceof BeanManager)) {
            throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR,
                                                         "beanManager instance should be of type '" + BeanManager.class + "'"));
        }
        this.beanManager = (BeanManager) beanManager;
    }

    /**
     * Creates an instance of the CDI managed bean.
     * Calls CDI API to inject into the bean.
     *
     * @param componentClass bean class to be instantiated.
     * @return New instance of bean class with injected content.
     */
    @Override
    @SuppressWarnings("unchecked")
    public  T getOrCreateComponent(Class componentClass) {
        return (T) injectionTargets.computeIfAbsent(componentClass, clazz -> {
            final AnnotatedType aType = beanManager.createAnnotatedType(componentClass);
            final InjectionTarget injectionTarget = beanManager.getInjectionTargetFactory(aType)
                    .createInjectionTarget(null);
            CreationalContext creationalContext = beanManager.createCreationalContext(null);
            final T beanInstance = injectionTarget.produce(creationalContext);
            injectionTarget.inject(beanInstance, creationalContext);
            injectionTarget.postConstruct(beanInstance);
            return new CDIManagedBean(beanInstance, injectionTarget, creationalContext);
        }).getInstance();
    }

    @Override
    public void close() throws IOException {
        injectionTargets.forEach((clazz, target) -> cleanupBean(target));
        injectionTargets.clear();
    }

    private  void cleanupBean(CDIManagedBean bean) {
        bean.getInjectionTarget().preDestroy(bean.getInstance());
        bean.getInjectionTarget().dispose(bean.getInstance());
        bean.getCreationalContext().release();
    }

    /**
     * Holder for bean instance and its injection target.
     */
    private static final class CDIManagedBean {
        private final T instance;
        private final InjectionTarget injectionTarget;
        private final CreationalContext creationalContext;

        CDIManagedBean(T instance, InjectionTarget injectionTarget, CreationalContext creationalContext) {
            this.instance = instance;
            this.injectionTarget = injectionTarget;
            this.creationalContext = creationalContext;
        }

        /**
         * @return CDI InjectionTarget
         */
        private InjectionTarget getInjectionTarget() {
            return injectionTarget;
        }

        /**
         * @return managed instance of a bean
         */
        private T getInstance() {
            return instance;
        }

        /**
         * @return creational context
         */
        private CreationalContext getCreationalContext() {
            return creationalContext;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy