Content of file ReflectionUtils.java.html

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ReflectionUtils.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">SteelBlue - JavaFX Bindings</a> &gt; <a href="index.source.html" class="el_package">it.tidalwave.role.ui.javafx.impl.util</a> &gt; <span class="el_source">ReflectionUtils.java</span></div><h1>ReflectionUtils.java</h1><pre class="source lang-java linenums">/*
 * *********************************************************************************************************************
 *
 * SteelBlue: DCI User Interfaces
 * http://tidalwave.it/projects/steelblue
 *
 * Copyright (C) 2015 - 2021 by Tidalwave s.a.s. (http://tidalwave.it)
 *
 * *********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * *********************************************************************************************************************
 *
 * git clone https://bitbucket.org/tidalwave/steelblue-src
 * git clone https://github.com/tidalwave-it/steelblue-src
 *
 * *********************************************************************************************************************
 */
package it.tidalwave.role.ui.javafx.impl.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import static java.util.stream.Collectors.toList;
import static it.tidalwave.role.spi.impl.LogUtil.*;

/***********************************************************************************************************************
 *
 * Just slightly adapted from http://www.artima.com/weblogs/viewpost.jsp?thread=208860
 *
 * TODO: Consider incorporating this in TFT.
Consider incorporating this in TFT.
* * @author Fabrizio Giudici * @author based on code of Ian Robertson * **********************************************************************************************************************/ <span class="nc" id="L60">@Slf4j @UtilityClass</span> <span class="nc" id="L61">public class ReflectionUtils</span> { /******************************************************************************************************************* * * * ******************************************************************************************************************/ public static void injectDependencies (@Nonnull final Object object, @Nonnull final Map&lt;Class&lt;?&gt;, Object&gt; beans) { <span class="nc bnc" id="L70" title="All 2 branches missed."> for (final Field field : object.getClass().getDeclaredFields())</span> { <span class="nc bnc" id="L72" title="All 2 branches missed."> if (field.getAnnotation(Inject.class) != null)</span> { <span class="nc" id="L74"> field.setAccessible(true);</span> <span class="nc" id="L75"> final Class&lt;?&gt; type = field.getType();</span> <span class="nc" id="L76"> final Object dependency = beans.get(type);</span> <span class="nc bnc" id="L78" title="All 2 branches missed."> if (dependency == null)</span> { <span class="nc" id="L80"> throw new RuntimeException(&quot;Can't inject &quot; + object + &quot;.&quot; + field.getName());</span> } try { <span class="nc" id="L85"> field.set(object, dependency);</span> } <span class="nc" id="L87"> catch (IllegalArgumentException | IllegalAccessException e)</span> { <span class="nc" id="L89"> throw new RuntimeException(e);</span> <span class="nc" id="L90"> }</span> } } <span class="nc" id="L93"> }</span> /******************************************************************************************************************* * * Instantiates an object of the given class performing dependency injections through the constructor. * * @param &lt;T&gt; the generic type of the object to instantiate * @param type the dynamic type of the object to instantiate; it is expected to have a single constructor * @param beans the pool of objects to instantiate * @return the new instance * @throws RuntimeException if something fails * ******************************************************************************************************************/ public static &lt;T&gt; T instantiateWithDependencies (@Nonnull final Class&lt;T&gt; type, @Nonnull final Map&lt;Class&lt;?&gt;, Object&gt; beans) { try { <span class="nc" id="L111"> log.debug(&quot;instantiateWithDependencies({}, {})&quot;, shortName(type), shortIds(beans.values()));</span> <span class="nc" id="L112"> final Constructor&lt;?&gt;[] constructors = type.getConstructors();</span> <span class="nc bnc" id="L114" title="All 2 branches missed."> if (constructors.length &gt; 1)</span> { <span class="nc" id="L116"> throw new RuntimeException(&quot;Multiple constructors in &quot; + type);</span> } <span class="nc" id="L119"> final List&lt;Object&gt; parameters =</span> <span class="nc" id="L120"> Arrays.stream(constructors[0].getParameterTypes()).map(beans::get).collect(toList());</span> <span class="nc" id="L122"> log.trace(&quot;&gt;&gt;&gt;&gt; ctor arguments: {}&quot;, shortIds(parameters));</span> <span class="nc" id="L123"> return type.cast(constructors[0].newInstance(parameters.toArray()));</span> } <span class="nc" id="L125"> catch (InstantiationException | IllegalAccessException | InvocationTargetException e)</span> { <span class="nc" id="L127"> throw new RuntimeException(e);</span> } } /******************************************************************************************************************* * * Get the actual type arguments a child class has used to extend a generic base class. * * @param baseClass the base class * @param childClass the child class * @return a list of the raw classes for the actual type arguments. * ******************************************************************************************************************/ public static &lt;T&gt; List&lt;Class&lt;?&gt;&gt; getTypeArguments (@Nonnull final Class&lt;T&gt; baseClass, @Nonnull final Class&lt;? extends T&gt; childClass) { <span class="nc" id="L143"> final Map&lt;Type, Type&gt; resolvedTypes = new HashMap&lt;&gt;();</span> <span class="nc" id="L144"> Type type = childClass;</span> // start walking up the inheritance hierarchy until we hit baseClass <span class="nc bnc" id="L147" title="All 2 branches missed."> while (!getClass(type).equals(baseClass))</span> { <span class="nc bnc" id="L149" title="All 2 branches missed."> if (type instanceof Class&lt;?&gt;)</span> { // there is no useful information for us in raw types, so just keep going. <span class="nc" id="L152"> type = ((Class&lt;?&gt;)type).getGenericSuperclass();</span> } else { <span class="nc" id="L156"> final ParameterizedType parameterizedType = (ParameterizedType) type;</span> <span class="nc" id="L157"> final Class&lt;?&gt; rawType = (Class) parameterizedType.getRawType();</span> <span class="nc" id="L158"> final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();</span> <span class="nc" id="L159"> final TypeVariable&lt;?&gt;[] typeParameters = rawType.getTypeParameters();</span> <span class="nc bnc" id="L161" title="All 2 branches missed."> for (int i = 0; i &lt; actualTypeArguments.length; i++)</span> { <span class="nc" id="L163"> resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);</span> } <span class="nc bnc" id="L166" title="All 2 branches missed."> if (!rawType.equals(baseClass))</span> { <span class="nc" id="L168"> type = rawType.getGenericSuperclass();</span> } <span class="nc" id="L170"> }</span> } // finally, for each actual type argument provided to baseClass, determine (if possible) // the raw class for that type argument. final Type[] actualTypeArguments; <span class="nc bnc" id="L177" title="All 2 branches missed."> if (type instanceof Class)</span> { <span class="nc" id="L179"> actualTypeArguments = ((Class)type).getTypeParameters();</span> } else { <span class="nc" id="L183"> actualTypeArguments = ((ParameterizedType)type).getActualTypeArguments();</span> } <span class="nc" id="L186"> final List&lt;Class&lt;?&gt;&gt; typeArgumentsAsClasses = new ArrayList&lt;&gt;();</span> // resolve types by chasing down type variables. <span class="nc bnc" id="L188" title="All 2 branches missed."> for (Type baseType : actualTypeArguments)</span> { <span class="nc bnc" id="L190" title="All 2 branches missed."> while (resolvedTypes.containsKey(baseType))</span> { <span class="nc" id="L192"> baseType = resolvedTypes.get(baseType);</span> } <span class="nc" id="L195"> typeArgumentsAsClasses.add(getClass(baseType));</span> } <span class="nc" id="L198"> return typeArgumentsAsClasses;</span> } /******************************************************************************************************************* * * * ******************************************************************************************************************/ @CheckForNull public static Class&lt;?&gt; getClass (@Nonnull final Type type) { <span class="nc bnc" id="L209" title="All 2 branches missed."> if (type instanceof Class&lt;?&gt;)</span> { <span class="nc" id="L211"> return (Class&lt;?&gt;)type;</span> } <span class="nc bnc" id="L213" title="All 2 branches missed."> else if (type instanceof ParameterizedType)</span> { <span class="nc" id="L215"> return getClass(((ParameterizedType)type).getRawType());</span> } <span class="nc bnc" id="L217" title="All 2 branches missed."> else if (type instanceof GenericArrayType)</span> { <span class="nc" id="L219"> final Type componentType = ((GenericArrayType)type).getGenericComponentType();</span> <span class="nc" id="L220"> final Class&lt;?&gt; componentClass = getClass(componentType);</span> <span class="nc bnc" id="L222" title="All 2 branches missed."> if (componentClass == null)</span> { <span class="nc" id="L224"> return null;</span> } <span class="nc" id="L227"> return Array.newInstance(componentClass, 0).getClass();</span> } else { <span class="nc" id="L231"> return null;</span> } } } </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>