protected Object createObject()

in ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java [700:896]


    protected Object createObject() {
        if (m_clazz == null) {
            load();
        }

        // The following code doesn't need to be synchronized as is deal only with immutable fields.
        Object instance = null;
        if (m_factoryMethod == null) {
            // No factory-method, we use the constructor.
            try {
                // Try to find the correct constructor.
                if (m_constructorRegistration != null) {
                    // Initialize the injected values and types
                    // We have the IM first.
                    Object[] values = new Object[m_constructorRegistration.size() + 1];
                    Class[] types = new Class[m_constructorRegistration.size() + 1];
                    values[0] = this;
                    types[0] = InstanceManager.class;

                    // Iterate over the constructor injector
                    for (int i = 0; i < m_constructorRegistration.size(); i++) {
                        ConstructorInjector injector = (ConstructorInjector)
                                m_constructorRegistration.get(new Integer(i));
                        Object v = injector.getConstructorParameter(i);
                        if (v != null) {
                            values[i + 1] = v;
                            Class t = injector.getConstructorParameterType(i);
                            if (t == null) {
                                t = v.getClass();
                            }
                            types[i + 1] = t;
                        }
                    }
                    // Find the constructor.
                    Constructor cst = m_clazz.getDeclaredConstructor(types);
                    if (!cst.isAccessible()) {
                        cst.setAccessible(true);
                    }
                    String methodId = MethodMetadata.computeMethodId(cst);
                    onEntry(null, methodId, values);
                    instance = cst.newInstance(values);
                    onExit(instance, methodId, instance);
                } else {
                    // Old semantic
                    // Try to find if there is a constructor with a bundle context as parameter :
                    try {
                        Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class, BundleContext.class});
                        if (!cst.isAccessible()) {
                            cst.setAccessible(true);
                        }
                        Object[] args = new Object[]{this, m_context};
                        onEntry(null, MethodMetadata.BC_CONSTRUCTOR_ID, new Object[]{m_context});
                        instance = cst.newInstance(args);
                        onExit(instance, MethodMetadata.BC_CONSTRUCTOR_ID, instance);
                    } catch (NoSuchMethodException e) {
                        // Create an instance if no instance are already created with <init>()BundleContext
                        if (instance == null) {
                            Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class});
                            if (!cst.isAccessible()) {
                                cst.setAccessible(true);
                            }
                            Object[] args = new Object[]{this};
                            onEntry(null, MethodMetadata.EMPTY_CONSTRUCTOR_ID, new Object[0]);
                            instance = cst.newInstance(args);
                            onExit(instance, MethodMetadata.EMPTY_CONSTRUCTOR_ID, instance);
                        }
                    }
                }

            } catch (IllegalAccessException e) {
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The POJO constructor is not accessible : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
            } catch (SecurityException e) {
                m_logger.log(
                        Logger.ERROR,
                        "["
                                + m_name
                                + "] createInstance -> The POJO constructor is not accessible (security reason) : "
                                + e.getMessage(), e
                );
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
            } catch (InvocationTargetException e) {
                m_logger.log(
                        Logger.ERROR,
                        "["
                                + m_name
                                + "] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : "
                                + e.getTargetException().getMessage(), e.getTargetException()
                );
                onError(null, m_className, e.getTargetException());
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor has thrown an exception", e.getTargetException());
            } catch (NoSuchMethodException e) {
                // Improve the log message because of FELIX-4455, we will see if we get better feedback.
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] iPOJO did not find a suitable constructor to create the " +
                                "object: " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor cannot be found", e);
            } catch (Throwable e) {
                // Catch every other possible error and runtime exception.
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The POJO constructor invocation failed : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor invocation has thrown an exception", e);
            }
        } else {
            try {
                // Build the pojo object with the factory-method.
                Method factory = null;
                // Try with the bundle context
                try {
                    factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[]{BundleContext.class});
                    if (!factory.isAccessible()) {
                        factory.setAccessible(true);
                    }
                    Object[] args = new Object[]{m_context};
                    onEntry(null, m_className, args);
                    instance = factory.invoke(null, new Object[]{m_context});
                } catch (NoSuchMethodException e1) {
                    // Try without the bundle context
                    try {
                        factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[0]);
                        if (!factory.isAccessible()) {
                            factory.setAccessible(true);
                        }
                        Object[] args = new Object[0];
                        onEntry(null, m_className, args);
                        instance = factory.invoke(null, args);
                    } catch (NoSuchMethodException e2) {
                        // Error : factory-method not found
                        m_logger.log(
                                Logger.ERROR,
                                "["
                                        + m_name
                                        + "] createInstance -> Cannot invoke the factory-method (method not found) : "
                                        + e2.getMessage(), e2
                        );
                        stop();
                        throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found", e2);
                    }
                }

                // Now call the setInstanceManager method.
                // Find declaring super class.
                Class declaringClass = instance.getClass();
                Method method = null;
                while (declaringClass != null && method == null) {
                    try {
                        method = declaringClass.getDeclaredMethod("_setInstanceManager",
                                new Class[]{InstanceManager.class});
                    } catch (NoSuchMethodException e) {
                        //Do nothing
                    }

                    declaringClass = declaringClass.getSuperclass();
                }

                if (method == null) {
                    // Error : _setInstanceManager method is missing
                    m_logger
                            .log(
                                    Logger.ERROR,
                                    "["
                                            + m_name
                                            + "] createInstance -> Cannot invoke the factory-method (the _setInstanceManager method does not exist"
                            );
                    stop();
                    throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found");
                }

                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                method.invoke(instance, new Object[]{this});
                onExit(null, m_className, instance);

            } catch (InvocationTargetException e) {
                // Error : invocation failed
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The factory-method throws an exception : " + e.getTargetException(), e.getTargetException());
                onError(null, m_className, e.getTargetException());
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the factory-method has thrown an exception", e.getTargetException());
            } catch (Throwable e) {
                // Catch every other possible error and runtime exception.
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The factory-method invocation failed : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the factory-method invocation has thrown an exception", e);
            }
        }
        return instance;
    }