You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2013/01/05 16:14:04 UTC

svn commit: r1429309 [3/3] - in /camel/trunk: components/camel-guice/ components/camel-guice/src/main/java/org/apache/camel/guice/ components/camel-guice/src/main/java/org/apache/camel/guice/impl/ components/camel-guice/src/main/java/org/apache/camel/g...

Added: camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/InjectorManager.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/InjectorManager.java?rev=1429309&view=auto
==============================================================================
--- camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/InjectorManager.java (added)
+++ camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/InjectorManager.java Sat Jan  5 15:14:02 2013
@@ -0,0 +1,238 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); 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 "AS IS" 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.
+ */
+package org.apache.camel.guice.testing;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+
+import org.apache.camel.guice.inject.Injectors;
+import org.apache.camel.guice.support.CloseErrors;
+import org.apache.camel.guice.support.CloseFailedException;
+import org.apache.camel.guice.support.internal.CloseErrorsImpl;
+import org.apache.camel.guice.util.CloseableScope;
+
+/**
+ * Used to manage the injectors for the various injection points
+ * 
+ */
+public class InjectorManager {
+    private static final String NESTED_MODULE_CLASS = "TestModule";
+
+    private Map<Object, Injector> injectors = new ConcurrentHashMap<Object, Injector>();
+    private AtomicInteger initializeCounter = new AtomicInteger(0);
+    private CloseableScope testScope = new CloseableScope(TestScoped.class);
+    private CloseableScope classScope = new CloseableScope(ClassScoped.class);
+    
+    private boolean closeSingletonsAfterClasses;
+    private boolean runFinalizer = true;
+    private Class<? extends Module> moduleType;
+
+    public void beforeClasses() {
+        int counter = initializeCounter.incrementAndGet();
+        if (counter > 1) {
+            System.out.println("WARNING! Initialised more than once! Counter: " + counter);
+        } else {
+            if (runFinalizer) {
+                Runtime.getRuntime().addShutdownHook(new Thread() {
+                    @Override
+                    public void run() {
+                        try {
+                            closeSingletons();
+                        } catch (Throwable e) {
+                            System.out.println("Failed to shut down Guice Singletons: " + e);
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        }
+
+    }
+
+    /** Lets close all of the injectors we have created so far */
+    public void afterClasses() throws CloseFailedException {
+        Injector injector = injectors.get(moduleType);
+        if (injector != null) {
+            classScope.close(injector);
+        } else {
+            System.out.println("Could not close Class scope as there is no Injector for module type "
+                               + injector);
+        }
+
+        // NOTE that we don't have any good hooks yet to call complete()
+        // when the JVM is completed to ensure real singletons shut down
+        // correctly
+        //
+        if (isCloseSingletonsAfterClasses()) {
+            closeInjectors();
+        }
+    }
+
+    public void beforeTest(Object test) throws Exception {
+        Preconditions.checkNotNull(test, "test");
+
+        Class<? extends Object> testType = test.getClass();
+        moduleType = getModuleForTestClass(testType);
+
+        Injector classInjector;
+        synchronized (injectors) {
+            classInjector = injectors.get(moduleType);
+            if (classInjector == null) {
+                classInjector = createInjector(moduleType);
+                Preconditions.checkNotNull(classInjector, "classInjector");
+                injectors.put(moduleType, classInjector);
+            }
+        }
+        injectors.put(testType, classInjector);
+
+        classInjector.injectMembers(test);
+    }
+
+    public void afterTest(Object test) throws Exception {
+        Injector injector = injectors.get(test.getClass());
+        if (injector == null) {
+            System.out.println("Warning - no injector available for: " + test);
+        } else {
+            testScope.close(injector);
+        }
+    }
+
+    /**
+     * Closes down any JVM level singletons used in this testing JVM
+     */
+    public void closeSingletons() throws CloseFailedException {
+        closeInjectors();
+    }
+
+    public boolean isCloseSingletonsAfterClasses() {
+        return closeSingletonsAfterClasses;
+    }
+
+    public void setCloseSingletonsAfterClasses(boolean closeSingletonsAfterClasses) {
+        this.closeSingletonsAfterClasses = closeSingletonsAfterClasses;
+    }
+
+    protected class TestModule extends AbstractModule {
+
+        protected void configure() {
+            bindScope(ClassScoped.class, classScope);
+            bindScope(TestScoped.class, testScope);
+        }
+    }
+
+    protected void closeInjectors() throws CloseFailedException {
+        CloseErrors errors = new CloseErrorsImpl(this);
+        Set<Entry<Object, Injector>> entries = injectors.entrySet();
+        for (Entry<Object, Injector> entry : entries) {
+            // Object key = entry.getKey();
+            Injector injector = entry.getValue();
+            Injectors.close(injector, errors);
+        }
+        injectors.clear();
+        errors.throwIfNecessary();
+    }
+
+    /**
+     * Factory method to return the module type that will be used to create an
+     * injector.
+     * 
+     * The default implementation will use the system property
+     * <code>org.guiceyfruit.modules</code> (see
+     * {@link Injectors#MODULE_CLASS_NAMES} otherwise if that is not set it will
+     * look for the {@link UseModule} annotation and use the module defined on
+     * that otherwise it will try look for the inner public static class
+     * "TestModule"
+     * 
+     * @see org.apache.camel.guice.testing.UseModule
+     * @see #NESTED_MODULE_CLASS
+     */
+    @SuppressWarnings("unchecked")
+    protected Class<? extends Module> getModuleForTestClass(Class<?> objectType)
+        throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        String modules = System.getProperty(Injectors.MODULE_CLASS_NAMES);
+        if (modules != null) {
+            modules = modules.trim();
+            if (modules.length() > 0) {
+                System.out.println("Overloading Guice Modules: " + modules);
+                return null;
+            }
+        }
+        Class<? extends Module> moduleType;
+        UseModule config = objectType.getAnnotation(UseModule.class);
+        if (config != null) {
+            moduleType = config.value();
+        } else {
+            String name = objectType.getName() + "$" + NESTED_MODULE_CLASS;
+            Class<?> type;
+            try {
+                type = objectType.getClassLoader().loadClass(name);
+            } catch (ClassNotFoundException e) {
+                try {
+                    type = Thread.currentThread().getContextClassLoader().loadClass(name);
+                } catch (ClassNotFoundException e2) {
+                    throw new ClassNotFoundException(
+                                                     "Class "
+                                                         + objectType.getName()
+                                                         + " does not have a @UseModule annotation nor does it have a nested class called "
+                                                         + NESTED_MODULE_CLASS
+                                                         + " available on the classpath. Please see: http://code.google.com/p/guiceyfruit/wiki/Testing"
+                                                         + e, e);
+                }
+            }
+            try {
+                moduleType = (Class<? extends Module>)type;
+            } catch (Exception e) {
+                throw new IllegalArgumentException("Class " + type.getName() + " is not a Guice Module!", e);
+            }
+        }
+        int modifiers = moduleType.getModifiers();
+        if (Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers)) {
+            throw new IllegalArgumentException("Class " + moduleType.getName()
+                                               + " must be a public class which is non abstract");
+        }
+        try {
+            moduleType.getConstructor();
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException("Class " + moduleType.getName()
+                                               + " must have a zero argument constructor", e);
+        }
+        return moduleType;
+    }
+
+    /**
+     * Creates the injector for the given key
+     */
+    protected Injector createInjector(Class<? extends Module> moduleType) throws InstantiationException,
+        IllegalAccessException, ClassNotFoundException {
+        if (moduleType == null) {
+            return Injectors.createInjector(System.getProperties(), new TestModule());
+        }
+        // System.out.println("Creating Guice Injector from module: " +
+        // moduleType.getName());
+        Module module = moduleType.newInstance();
+        return Guice.createInjector(module, new TestModule());
+    }
+}

Added: camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/TestScoped.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/TestScoped.java?rev=1429309&view=auto
==============================================================================
--- camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/TestScoped.java (added)
+++ camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/TestScoped.java Sat Jan  5 15:14:02 2013
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); 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 "AS IS" 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.
+ */
+package org.apache.camel.guice.testing;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.google.inject.Scope;
+import com.google.inject.ScopeAnnotation;
+
+/**
+ * This defines a {@link Scope} that lasts for a single test run.
+ * 
+ * <p>
+ * A test conceptually comes in scope when it starts and goes out of scope when
+ * it finishes its execution (e.g., on JUnit lingo, roughly at the moment of
+ * {@link junit.framework.TestCase#setUp()} and
+ * {@link junit.framework.TestCase#tearDown()}).
+ * 
+ * @author Luiz-Otavio Zorzella
+ * @author Danka Karwanska
+ * @see org.apache.camel.guice.util.CloseableScope for an implementation of this
+ *      scope
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@ScopeAnnotation
+public @interface TestScoped {
+}
\ No newline at end of file

Copied: camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/UseModule.java (from r1429285, camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/ConciseGuiceRouteTest.java)
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/UseModule.java?p2=camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/UseModule.java&p1=camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/ConciseGuiceRouteTest.java&r1=1429285&r2=1429309&rev=1429309&view=diff
==============================================================================
--- camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/ConciseGuiceRouteTest.java (original)
+++ camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/UseModule.java Sat Jan  5 15:14:02 2013
@@ -14,25 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.guice;
+package org.apache.camel.guice.testing;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import org.junit.Assert;
-import org.junit.Test;
-/**
- * Uses a RouteBuilder to bind instances of routes to the CamelContext
- *
- * @version 
- */
-public class ConciseGuiceRouteTest extends Assert {
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.Module;
 
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testGuice() throws Exception {
-        // lets disable resource injection to avoid JNDI being used
-        Injector injector = Guice.createInjector(new CamelModuleWithRouteTypes(MyRouteInstaller.class, MyHardcodeRoute.class));
-        GuiceTest.assertCamelContextRunningThenCloseInjector(injector);
-    }
 
-}
\ No newline at end of file
+
+/**
+ * Specifies the default Guice Module to use when running the test case when
+ * using <a href="http://code.google.com/p/guiceyfruit/wiki/Testing">Guicey
+ * Testing</a>
+ * 
+ */
+@Target({ TYPE })
+@Retention(RUNTIME)
+@Documented
+public @interface UseModule {
+    Class<? extends Module> value();
+}

Added: camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/junit4/GuiceyJUnit4.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/junit4/GuiceyJUnit4.java?rev=1429309&view=auto
==============================================================================
--- camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/junit4/GuiceyJUnit4.java (added)
+++ camel/trunk/components/camel-guice/src/test/java/org/apache/camel/guice/testing/junit4/GuiceyJUnit4.java Sat Jan  5 15:14:02 2013
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); 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 "AS IS" 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.
+ */
+package org.apache.camel.guice.testing.junit4;
+
+import org.apache.camel.guice.testing.InjectorManager;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+public class GuiceyJUnit4 extends BlockJUnit4ClassRunner {
+
+    protected static InjectorManager manager = new InjectorManager();
+
+    public GuiceyJUnit4(Class<?> aClass) throws InitializationError {
+        super(aClass);
+    }
+
+    @Override
+    protected Statement withBeforeClasses(Statement statement) {
+        final Statement parent = super.withBeforeClasses(statement);
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                manager.beforeClasses();
+
+                parent.evaluate();
+            }
+        };
+    }
+
+    @Override
+    protected Statement withAfterClasses(Statement statement) {
+        final Statement parent = super.withAfterClasses(statement);
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                parent.evaluate();
+
+                manager.afterClasses();
+            }
+        };
+    }
+
+    @Override
+    protected Statement withBefores(FrameworkMethod frameworkMethod, final Object test, Statement statement) {
+        @SuppressWarnings("deprecation")
+        final Statement parent = super.withBefores(frameworkMethod, test, statement);
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                manager.beforeTest(test);
+
+                parent.evaluate();
+            }
+        };
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    protected Statement withAfters(FrameworkMethod frameworkMethod, final Object test, Statement statement) {
+        final Statement parent = super.withBefores(frameworkMethod, test, statement);
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                parent.evaluate();
+
+                manager.afterTest(test);
+            }
+        };
+    }
+
+    @Override
+    public void run(RunNotifier runNotifier) {
+        super.run(runNotifier);
+    }
+}

Modified: camel/trunk/components/camel-guice/src/test/resources/jndi.properties
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-guice/src/test/resources/jndi.properties?rev=1429309&r1=1429308&r2=1429309&view=diff
==============================================================================
--- camel/trunk/components/camel-guice/src/test/resources/jndi.properties (original)
+++ camel/trunk/components/camel-guice/src/test/resources/jndi.properties Sat Jan  5 15:14:02 2013
@@ -21,7 +21,7 @@
 #
 
 # Guice JNDI provider
-java.naming.factory.initial = org.guiceyfruit.jndi.GuiceInitialContextFactory
+java.naming.factory.initial = org.apache.camel.guice.jndi.GuiceInitialContextFactory
 
 # list of guice modules to boot up (space separated)
 org.guiceyfruit.modules = org.apache.camel.guice.CamelModuleWithMatchingRoutes

Modified: camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/MyModule.java
URL: http://svn.apache.org/viewvc/camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/MyModule.java?rev=1429309&r1=1429308&r2=1429309&view=diff
==============================================================================
--- camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/MyModule.java (original)
+++ camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/MyModule.java Sat Jan  5 15:14:02 2013
@@ -19,16 +19,16 @@ package org.apache.camel.example.guice.j
 import com.google.inject.Injector;
 import com.google.inject.Provides;
 import com.google.inject.name.Named;
+
 import org.apache.activemq.ActiveMQConnectionFactory;
 import org.apache.camel.component.jms.JmsComponent;
 import org.apache.camel.guice.CamelModuleWithMatchingRoutes;
-import org.guiceyfruit.jndi.JndiBind;
+import org.apache.camel.guice.jndi.JndiBind;
 
 /**
  * Configures the CamelContext, RouteBuilder, Component and Endpoint instances using
  * Guice
  *
- * @version 
  */
 public class MyModule extends CamelModuleWithMatchingRoutes {
 

Modified: camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/OSGiCamelContextProvider.java
URL: http://svn.apache.org/viewvc/camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/OSGiCamelContextProvider.java?rev=1429309&r1=1429308&r2=1429309&view=diff
==============================================================================
--- camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/OSGiCamelContextProvider.java (original)
+++ camel/trunk/examples/camel-example-guice-jms/src/main/java/org/apache/camel/example/guice/jms/OSGiCamelContextProvider.java Sat Jan  5 15:14:02 2013
@@ -15,22 +15,23 @@
  * limitations under the License.
  */
 package org.apache.camel.example.guice.jms;
-
 import java.util.Properties;
 import java.util.Set;
+
 import javax.naming.Context;
 
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.RoutesBuilder;
+import org.apache.camel.guice.jndi.JndiBindings;
+import org.apache.camel.guice.jndi.internal.JndiContext;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.impl.JndiRegistry;
 import org.apache.camel.osgi.CamelContextFactory;
-import org.guiceyfruit.jndi.JndiBindings;
-import org.guiceyfruit.jndi.internal.JndiContext;
 import org.osgi.framework.BundleContext;
 
 public class OSGiCamelContextProvider implements Provider<CamelContext> {

Modified: camel/trunk/examples/camel-example-guice-jms/src/main/resources/guicejndi.properties
URL: http://svn.apache.org/viewvc/camel/trunk/examples/camel-example-guice-jms/src/main/resources/guicejndi.properties?rev=1429309&r1=1429308&r2=1429309&view=diff
==============================================================================
--- camel/trunk/examples/camel-example-guice-jms/src/main/resources/guicejndi.properties (original)
+++ camel/trunk/examples/camel-example-guice-jms/src/main/resources/guicejndi.properties Sat Jan  5 15:14:02 2013
@@ -21,7 +21,7 @@
 #
 
 # Guice JNDI provider
-java.naming.factory.initial = org.guiceyfruit.jndi.GuiceInitialContextFactory
+java.naming.factory.initial =  org.apache.camel.guice.jndi.GuiceInitialContextFactory
 
 # list of guice modules to boot up (space separated)
 org.guiceyfruit.modules = org.apache.camel.example.guice.jms.MyModule

Modified: camel/trunk/parent/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/parent/pom.xml?rev=1429309&r1=1429308&r2=1429309&view=diff
==============================================================================
--- camel/trunk/parent/pom.xml (original)
+++ camel/trunk/parent/pom.xml Sat Jan  5 15:14:02 2013
@@ -138,12 +138,13 @@
     <geronimo-ws-metadata-spec-version>1.1.3</geronimo-ws-metadata-spec-version>
     <gmaven-plugin-version>1.4</gmaven-plugin-version>
     <google-app-engine-version>1.6.6</google-app-engine-version>
+    <google-collections-version>1.0</google-collections-version>
     <google-gdata-version>1.41.5.w1</google-gdata-version>
     <google-guava-version>13.0.1</google-guava-version>
     <groovy-version>2.0.6</groovy-version>
     <gson-version>2.2.2</gson-version>
-    <guice-bundle-version>2.0_2</guice-bundle-version>
-    <guiceyfruit-version>2.0</guiceyfruit-version>
+    <guice-bundle-version>3.0_2</guice-bundle-version>
+    <guice-version>3.0</guice-version>
     <hadoop-bundle-version>1.0.4_1</hadoop-bundle-version>
     <hadoop-version>1.0.4</hadoop-version>
     <hamcrest-version>1.3</hamcrest-version>
@@ -1476,9 +1477,14 @@
 
       <!-- optional guice dependencies -->
       <dependency>
-        <groupId>org.guiceyfruit</groupId>
-        <artifactId>guiceyfruit-core</artifactId>
-        <version>${guiceyfruit-version}</version>
+        <groupId>com.google.inject</groupId>
+        <artifactId>guice</artifactId>
+        <version>${guice-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.google.collections</groupId>
+        <artifactId>google-collections</artifactId>
+        <version>${google-collections-version}</version>
       </dependency>
 
       <!-- optional castor dependencies -->