Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithRuntimeException.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithRuntimeException.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithRuntimeException.java (revision ) @@ -0,0 +1,47 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import javax.annotation.PostConstruct; + +/** + * Class with lifecycle method declaring a runtime exception, this is allowed. + */ +public class LifecycleWithRuntimeException extends LifecycleBase { + + @PostConstruct + public void init() throws IllegalStateException { + event("LifecycleWithRuntimeException.init"); + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithParameters.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithParameters.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithParameters.java (revision ) @@ -0,0 +1,46 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import javax.annotation.PostConstruct; + +/** + * Class with lifecycle method taking parameters, this is not allowed. + */ +public class LifecycleWithParameters extends LifecycleBase { + + @PostConstruct + public void init(String string) { + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithStaticMethod.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithStaticMethod.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithStaticMethod.java (revision ) @@ -0,0 +1,49 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import javax.annotation.PostConstruct; + +/** + * Class with annotated static methods, this method will not be invoked. + */ +public class LifecycleWithStaticMethod extends LifecycleBase { + + public static int invocations = 0; + + @PostConstruct + public static void init() { + invocations++; + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithWrongReturnType.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithWrongReturnType.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithWrongReturnType.java (revision ) @@ -0,0 +1,47 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import javax.annotation.PostConstruct; + +/** + * Class with lifecycle method with a return type other than void, this is not allowed. + */ +public class LifecycleWithWrongReturnType extends LifecycleBase { + + @PostConstruct + public String init() { + return null; + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithCheckedException.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithCheckedException.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleWithCheckedException.java (revision ) @@ -0,0 +1,48 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import java.sql.SQLException; + +import javax.annotation.PostConstruct; + +/** + * Class with lifecycle method declaring a checked exception, this is not allowed. + */ +public class LifecycleWithCheckedException extends LifecycleBase { + + @PostConstruct + public void init() throws SQLException { + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleThrowingRuntimeException.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleThrowingRuntimeException.java (revision ) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/LifecycleThrowingRuntimeException.java (revision ) @@ -0,0 +1,48 @@ +/** + * This file Copyright (c) 2012-2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice.lifecycle; + +import javax.annotation.PostConstruct; + +/** + * Class with lifecycle method throwing runtime exception, this is allowed. + */ +public class LifecycleThrowingRuntimeException extends LifecycleBase { + + @PostConstruct + public void init() { + event("LifecycleThrowingRuntimeException.init"); + throw new NullPointerException(); + } +} Index: magnolia-core/src/main/java/info/magnolia/objectfactory/guice/GuiceComponentProviderBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/main/java/info/magnolia/objectfactory/guice/GuiceComponentProviderBuilder.java (revision a6342742aed04a2df547665dd63603a42d25ff00) +++ magnolia-core/src/main/java/info/magnolia/objectfactory/guice/GuiceComponentProviderBuilder.java (revision ) @@ -52,7 +52,6 @@ import com.google.inject.Module; import com.google.inject.Stage; import com.google.inject.util.Modules; -import com.mycila.inject.jsr250.Jsr250; /** * Builder for creating a GuiceComponentProvider. @@ -121,8 +120,7 @@ // Components aren't available yet if (Boolean.valueOf(SystemProperty.getProperty("magnolia.jsr250.enabled", "true"))) { - // JSR-250 support added by Mycila - install(Jsr250.newJsr250Module()); + install(new PostConstructModule()); } install(new GuiceComponentConfigurationModule(configuration)); Index: magnolia-core/src/main/java/info/magnolia/objectfactory/guice/PostConstructModule.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/main/java/info/magnolia/objectfactory/guice/PostConstructModule.java (revision ) +++ magnolia-core/src/main/java/info/magnolia/objectfactory/guice/PostConstructModule.java (revision ) @@ -0,0 +1,197 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.objectfactory.guice; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import javax.annotation.PostConstruct; + +import com.google.inject.AbstractModule; +import com.google.inject.MembersInjector; +import com.google.inject.ProvisionException; +import com.google.inject.TypeLiteral; +import com.google.inject.matcher.Matchers; +import com.google.inject.spi.TypeEncounter; +import com.google.inject.spi.TypeListener; + +/** + * Implements support the JSR250 @PostConstruct annotation. + */ +public class PostConstructModule extends AbstractModule { + + @Override + protected void configure() { + bindListener(Matchers.any(), new TypeListener() { + + @Override + public void hear(final TypeLiteral type, final TypeEncounter encounter) { + + List postConstructMethods = findPostConstructMethods(type.getRawType()); + + // Add the custom injector only if there's annotated methods in this class + if (!postConstructMethods.isEmpty()) { + + final Method[] methods = postConstructMethods.toArray(new Method[postConstructMethods.size()]); + + encounter.register(new MembersInjector() { + + @Override + public void injectMembers(I injectee) { + + for (Method method : methods) { + try { + if (!method.isAccessible()) { + method.setAccessible(true); + } + method.invoke(injectee); + } catch (InvocationTargetException e) { + Throwable targetException = e.getTargetException(); + throw new ProvisionException("Exception caught invoking @PostConstruct initializer method [" + method + "]", targetException); + } catch (IllegalAccessException e) { + throw new ProvisionException("Exception caught invoking @PostConstruct initializer method [" + method + "]", e); + } + } + } + }); + } + } + + /** + * Returns the methods in a class that are annotated with @PostConstruct, fulfills the rules of JSR250 + * and are not overridden. The methods are ordered in the order they should be invoked, that is, they're + * ordered by their depth in the class hierarchy. + */ + private List findPostConstructMethods(Class clazz) { + LinkedList methods = new LinkedList(); + Class targetClass = clazz; + while (targetClass != Object.class) { + Method[] declaredMethods = targetClass.getDeclaredMethods(); + for (Method declaredMethod : declaredMethods) { + if (isLifecycleMethod(declaredMethod, PostConstruct.class, clazz)) { + methods.addFirst(declaredMethod); + } + } + targetClass = targetClass.getSuperclass(); + } + + return methods; + } + + /** + * Tests if the method fulfills the rules specified in JSR250 for methods annotated with + * @PostConstruct or @PreDestroy. + * + * @throws IllegalStateException if the method does not fulfill the rules + */ + private boolean isLifecycleMethod(Method method, Class annotation, Class clazz) { + if (!method.isAnnotationPresent(annotation)) { + return false; + } + if (Modifier.isStatic(method.getModifiers())) { + return false; + } + if (isOverridden(method, clazz)) { + return false; + } + if (!method.getReturnType().equals(Void.TYPE)) { + throw new IllegalStateException("Method annotated with @" + annotation.getSimpleName() + " must return void [" + method + "]"); + } + if (method.getParameterTypes().length != 0) { + throw new IllegalStateException("Method annotated with @" + annotation.getSimpleName() + " must not declare parameters [" + method + "]"); + } + for (Class exceptionType : method.getExceptionTypes()) { + if (!RuntimeException.class.isAssignableFrom(exceptionType) && !Error.class.isAssignableFrom(exceptionType)) { + throw new IllegalStateException("Method annotated with @" + annotation.getSimpleName() + " must not throw checked exceptions [" + method + "]"); + } + } + return true; + } + + /** + * Tests if a method is overridden in the class hierarchy of the given clazz. This method should be + * called with a method appearing in a super class of the supplied clazz. + */ + private boolean isOverridden(Method method, Class clazz) { + if (method.getDeclaringClass().equals(clazz)) { + return false; + } + int modifiers = method.getModifiers(); + if (Modifier.isPrivate(modifiers)) { + return false; + } + Class targetClass = clazz; + do { + for (Method declaredMethod : targetClass.getDeclaredMethods()) { + if (overrides(declaredMethod, method)) { + return true; + } + } + targetClass = clazz.getSuperclass(); + } while (targetClass != null && !targetClass.equals(method.getDeclaringClass())); + return false; + } + + /** + * Returns true if a method overrides another method. + */ + private boolean overrides(Method method, Method methodInSuperclass) { + + // Must have the same signatures + if (!(method.getName().equals(methodInSuperclass.getName()) && Arrays.equals(method.getParameterTypes(), methodInSuperclass.getParameterTypes()))) { + return false; + } + + // See JLS section 8.4.8.1 + int modifiers = methodInSuperclass.getModifiers(); + if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) { + return true; + } + + if (Modifier.isPrivate(modifiers)) { + return false; + } + + // methodInSuperclass is package-private, then its only overridden if the classes declaring these methods are in the same package + return method.getDeclaringClass().getPackage().equals(methodInSuperclass.getDeclaringClass().getPackage()); + } + + }); + } +} Index: magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/GuiceComponentProviderLifecycleTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/GuiceComponentProviderLifecycleTest.java (revision a6342742aed04a2df547665dd63603a42d25ff00) +++ magnolia-core/src/test/java/info/magnolia/objectfactory/guice/lifecycle/GuiceComponentProviderLifecycleTest.java (revision ) @@ -43,11 +43,15 @@ import static org.junit.Assert.fail; import info.magnolia.objectfactory.configuration.ComponentProviderConfiguration; +import info.magnolia.objectfactory.configuration.ImplementationConfiguration; import info.magnolia.objectfactory.guice.GuiceComponentProvider; import info.magnolia.objectfactory.guice.GuiceComponentProviderBuilder; import info.magnolia.objectfactory.guice.lifecycle.packageprotected.LifecycleExtendsClassWithPackageProtectedMethods; import info.magnolia.objectfactory.guice.lifecycle.packageprotected.LifecyclePackageProtectedMethod; +import com.google.inject.CreationException; +import com.google.inject.ProvisionException; + /** * This test case makes sure that @PostConstruct and @PreDestroy is implemented according to JSR250 when used in a class * hierarchy and on private and package protected methods. @@ -362,10 +366,95 @@ } } - private GuiceComponentProvider createProvider(Class clazz) { + @Test + public void testLifecycleOnClassWithStaticMethod() { + + // GIVEN + LifecycleWithStaticMethod.invocations = 0; + GuiceComponentProvider p = createProvider(LifecycleWithStaticMethod.class); + + // WHEN + p.getComponent(LifecycleWithStaticMethod.class); + + // THEN + assertEquals(0, LifecycleWithStaticMethod.invocations); + } + + @Test + public void testLifecycleWithWrongReturnType() { + + // WHEN + try { + createProvider(LifecycleWithWrongReturnType.class); + fail(); + } catch (CreationException e) { + // THEN + assertTrue(e.getMessage().contains("Reason: java.lang.IllegalStateException: Method annotated with @PostConstruct must return void [public java.lang.String info.magnolia.objectfactory.guice.lifecycle.LifecycleWithWrongReturnType.init()]")); + } + } + + @Test + public void testLifecycleWithParameters() { + + // WHEN + try { + createProvider(LifecycleWithParameters.class); + fail(); + } catch (CreationException e) { + // THEN + assertTrue(e.getMessage().contains("Reason: java.lang.IllegalStateException: Method annotated with @PostConstruct must not declare parameters [public void info.magnolia.objectfactory.guice.lifecycle.LifecycleWithParameters.init(java.lang.String)]")); + } + } + + @Test + public void testLifecycleWithCheckedException() { + + // WHEN + try { + createProvider(LifecycleWithCheckedException.class); + fail(); + } catch (CreationException e) { + e.printStackTrace(); + // THEN + assertTrue(e.getMessage().contains("Reason: java.lang.IllegalStateException: Method annotated with @PostConstruct must not throw checked exceptions [public void info.magnolia.objectfactory.guice.lifecycle.LifecycleWithCheckedException.init() throws java.sql.SQLException]")); + } + } + + @Test + public void testLifecycleWithRuntimeException() { + + // GIVEN + GuiceComponentProvider p = createProvider(LifecycleWithRuntimeException.class); + + // WHEN + p.getComponent(LifecycleWithRuntimeException.class); + + // THEN + assertEvent("LifecycleWithRuntimeException.init"); + assertNoMoreEvents(); + } + + @Test + public void testLifecycleThrowingRuntimeException() { + + // GIVEN + GuiceComponentProvider p = createProvider(LifecycleThrowingRuntimeException.class); + + // WHEN + try { + p.getComponent(LifecycleThrowingRuntimeException.class); + fail(); + } catch (ProvisionException e) { + assertTrue(e.getMessage().contains("Exception caught invoking @PostConstruct initializer method [public void info.magnolia.objectfactory.guice.lifecycle.LifecycleThrowingRuntimeException.init()]")); + } + } + + private GuiceComponentProvider createProvider(Class clazz) { ComponentProviderConfiguration configuration = new ComponentProviderConfiguration(); configuration.registerInstance(List.class, events); - configuration.registerImplementation(clazz); + ImplementationConfiguration id = ImplementationConfiguration.valueOf(clazz, clazz); + id.setLazy(true); + configuration.addComponent(id); return new GuiceComponentProviderBuilder().withConfiguration(configuration).build(); } Index: magnolia-core/src/main/java/info/magnolia/api/NewInstanceTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- magnolia-core/src/main/java/info/magnolia/api/NewInstanceTest.java (revision ) +++ magnolia-core/src/main/java/info/magnolia/api/NewInstanceTest.java (revision ) @@ -0,0 +1,136 @@ +/** + * This file Copyright (c) 2013 Magnolia International + * Ltd. (http://www.magnolia-cms.com). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia-cms.com/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.api; + +import info.magnolia.objectfactory.guice.PostConstructModule; + +import javax.annotation.PostConstruct; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Stage; +import com.mycila.inject.jsr250.Jsr250; + +/** + * . + */ +public class NewInstanceTest { + + private static long invocations; + + /** + * . + */ + public static class TestClassWithPostConstruct { + + public void method1() { + } + + public void method2() { + } + + @PostConstruct + public void method3() { + invocations++; + } + + public void method4() { + } + } + + /** + * . + */ + public static class TestClassWithoutPostConstruct { + + public void method1() { + } + + public void method2() { + } + + public void method3() { + } + + public void method4() { + } + } + + public static void main(String[] args) { + + int n = 1 * 1000 * 1000; + + System.out.println("To create " + n + " instances of a class with a @PostConstruct method"); + time("without Mycila", n, createSimpleInjector(), TestClassWithPostConstruct.class); + time("with Mycila", n, createInjectorWithMycila(), TestClassWithPostConstruct.class); + time("with Awesomeness", n, createAwesomeInjector(), TestClassWithPostConstruct.class); + System.out.println(); + + System.out.println("To create " + n + " instances of a class without @PostConstruct method"); + time("without Mycila", n, createSimpleInjector(), TestClassWithoutPostConstruct.class); + time("with Mycila", n, createInjectorWithMycila(), TestClassWithoutPostConstruct.class); + time("with Awesomeness", n, createAwesomeInjector(), TestClassWithoutPostConstruct.class); + } + + private static void time(String name, int n, Injector injector, Class clazz) { + + for (int i = 0; i < 1000 * 1000; i++) { + injector.getInstance(clazz); + } + + invocations = 0; + long start = System.currentTimeMillis(); + + for (int i = 0; i < n; i++) { + injector.getInstance(clazz); + } + + long end = System.currentTimeMillis(); + + System.out.println("Time " + name + ": " + (end - start) + " ms " + invocations + " invocations"); + } + + private static Injector createInjectorWithMycila() { + return Guice.createInjector(Stage.PRODUCTION, Jsr250.newJsr250Module()); + } + + private static Injector createSimpleInjector() { + return Guice.createInjector(Stage.PRODUCTION); + } + + private static Injector createAwesomeInjector() { + return Guice.createInjector(Stage.PRODUCTION, new PostConstructModule()); + } + +}