Merge pull request #839 from magnayn/master

Allow JPA properties to be Objects as well as simple strings.
diff --git a/extensions/persist/pom.xml b/extensions/persist/pom.xml
index a560f38..d65b014 100644
--- a/extensions/persist/pom.xml
+++ b/extensions/persist/pom.xml
@@ -15,9 +15,9 @@
 
   <dependencies>
     <dependency>
-      <groupId>javax.persistence</groupId>
-      <artifactId>persistence-api</artifactId>
-      <version>1.0</version>
+      <groupId>org.hibernate.javax.persistence</groupId>
+      <artifactId>hibernate-jpa-2.0-api</artifactId>
+      <version>1.0.0.Final</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
@@ -35,7 +35,7 @@
     <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-entitymanager</artifactId>
-      <version>3.4.0.GA</version>
+      <version>4.1.7.Final</version>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistModule.java b/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistModule.java
index b318b27..027a018 100644
--- a/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistModule.java
+++ b/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistModule.java
@@ -19,7 +19,9 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
+import com.google.inject.Provides;
 import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
 import com.google.inject.persist.PersistModule;
 import com.google.inject.persist.PersistService;
 import com.google.inject.persist.UnitOfWork;
@@ -35,7 +37,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.List;
-import java.util.Properties;
+import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
@@ -54,19 +56,12 @@
     this.jpaUnit = jpaUnit;
   }
 
-  private Properties properties;
+  private Map<?,?> properties;
   private MethodInterceptor transactionInterceptor;
 
   @Override protected void configurePersistence() {
     bindConstant().annotatedWith(Jpa.class).to(jpaUnit);
 
-    if (null != properties) {
-      bind(Properties.class).annotatedWith(Jpa.class).toInstance(properties);
-    } else {
-      bind(Properties.class).annotatedWith(Jpa.class)
-          .toProvider(Providers.<Properties>of(null));
-    }
-
     bind(JpaPersistService.class).in(Singleton.class);
 
     bind(PersistService.class).to(JpaPersistService.class);
@@ -88,13 +83,17 @@
     return transactionInterceptor;
   }
 
+  @Provides @Jpa Map<?, ?> provideProperties() {
+    return properties;
+  }
+
   /**
    * Configures the JPA persistence provider with a set of properties.
    * 
    * @param properties A set of name value pairs that configure a JPA persistence
    * provider as per the specification.
    */
-  public JpaPersistModule properties(Properties properties) {
+  public JpaPersistModule properties(Map<?,?> properties) {
     this.properties = properties;
     return this;
   }
diff --git a/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistService.java b/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistService.java
index e0cb992..190506c 100644
--- a/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistService.java
+++ b/extensions/persist/src/com/google/inject/persist/jpa/JpaPersistService.java
@@ -29,7 +29,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.Properties;
+import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
@@ -43,11 +43,11 @@
   private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();
 
   private final String persistenceUnitName;
-  private final Properties persistenceProperties;
+  private final Map<?,?> persistenceProperties;
 
   @Inject
   public JpaPersistService(@Jpa String persistenceUnitName,
-      @Nullable @Jpa Properties persistenceProperties) {
+      @Nullable @Jpa Map<?,?> persistenceProperties) {
     this.persistenceUnitName = persistenceUnitName;
     this.persistenceProperties = persistenceProperties;
   }
diff --git a/extensions/persist/test/META-INF/persistence.xml b/extensions/persist/test/META-INF/persistence.xml
index 3b08af0..881c7fd 100644
--- a/extensions/persist/test/META-INF/persistence.xml
+++ b/extensions/persist/test/META-INF/persistence.xml
@@ -25,5 +25,19 @@
         </properties>
     </persistence-unit>
 
+    <persistence-unit name="testProperties" transaction-type="RESOURCE_LOCAL">
+        <provider>org.hibernate.ejb.HibernatePersistence</provider>
+
+        <class>com.google.inject.persist.jpa.JpaTestEntity</class>
+        <class>com.google.inject.persist.jpa.JpaParentTestEntity</class>
+        <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+        <properties>
+            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
+            <property name="hibernate.id.new_generator_mappings" value="true"/>
+            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
+        </properties>
+    </persistence-unit>
+
 </persistence>
 
diff --git a/extensions/persist/test/com/google/inject/persist/jpa/EnsureJpaCanTakeObjectsInPropertiesTest.java b/extensions/persist/test/com/google/inject/persist/jpa/EnsureJpaCanTakeObjectsInPropertiesTest.java
new file mode 100644
index 0000000..c5421a5
--- /dev/null
+++ b/extensions/persist/test/com/google/inject/persist/jpa/EnsureJpaCanTakeObjectsInPropertiesTest.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed 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 com.google.inject.persist.jpa;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+import com.google.inject.persist.UnitOfWork;
+
+import junit.framework.TestCase;
+
+import org.hibernate.cfg.Environment;
+import org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider;
+import org.hsqldb.jdbc.JDBCDataSource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+import javax.sql.DataSource;
+
+public class EnsureJpaCanTakeObjectsInPropertiesTest extends TestCase {
+
+  private Injector injector;
+
+  public static class DBModule extends AbstractModule {
+
+    final DataSource ds;
+    final boolean passDataSource;
+
+    DBModule(DataSource ds, boolean passDataSource) {
+      this.ds = ds;
+      this.passDataSource = passDataSource;
+    }
+
+    @Override
+    protected void configure() {
+      Map<String, Object> p = new HashMap<String, Object>();
+
+      p.put(Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName());
+      if (passDataSource) {
+        p.put(Environment.DATASOURCE, ds);
+      }
+
+      JpaPersistModule jpaPersistModule = new JpaPersistModule("testProperties").properties(p);
+
+      install(jpaPersistModule);
+    }
+  }
+
+  @Override
+  public void setUp() {
+    injector = null;
+  }
+
+  @Override
+  public final void tearDown() {
+    if (injector == null) {
+      return;
+    }
+
+    injector.getInstance(UnitOfWork.class).end();
+    injector.getInstance(EntityManagerFactory.class).close();
+  }
+
+  private static JDBCDataSource getDataSource() {
+    final JDBCDataSource dataSource = new JDBCDataSource();
+    dataSource.setDatabase("jdbc:hsqldb:mem:persistence");
+    dataSource.setUser("sa");
+    dataSource.setPassword("");
+    return dataSource;
+  }
+
+  private void startPersistService(boolean passDataSource) {
+    final JDBCDataSource dataSource = getDataSource();
+
+    injector = Guice.createInjector(new DBModule(dataSource, passDataSource));
+
+    //startup persistence
+    injector.getInstance(PersistService.class).start();
+  }
+
+  public void testWorksIfPassDataSource() {
+    startPersistService(true);
+  }
+
+  public void testFailsIfNoDataSource() {
+    try {
+      startPersistService(false);
+      fail();
+    } catch (PersistenceException ex) {
+      // Expected
+      injector = null;
+    }
+  }
+
+}
diff --git a/extensions/persist/test/com/google/inject/persist/jpa/JpaWorkManagerTest.java b/extensions/persist/test/com/google/inject/persist/jpa/JpaWorkManagerTest.java
index 1bdbf97..84dff07 100644
--- a/extensions/persist/test/com/google/inject/persist/jpa/JpaWorkManagerTest.java
+++ b/extensions/persist/test/com/google/inject/persist/jpa/JpaWorkManagerTest.java
@@ -24,6 +24,7 @@
 import com.google.inject.persist.UnitOfWork;
 
 import junit.framework.TestCase;
+import org.hibernate.HibernateException;
 
 import java.util.Date;
 
@@ -50,7 +51,11 @@
 
   @Override
   public void tearDown() {
-    injector.getInstance(EntityManagerFactory.class).close();
+    try {
+      injector.getInstance(EntityManagerFactory.class).close();
+    } catch(HibernateException ex) {
+        // Expected if the persist service has already been stopped.
+    }
   }
 
   public void testWorkManagerInSession() {