+ * Note that using this mechanism is only recommended for development;
+ * production applications should ideally be enhanced at build time, or at least
+ * load the agent via the javaagent JVM option. When the agent is
+ * loaded at runtime via this class, any entity classes that have already been
+ * loaded won't be enhanced and will fail to work correctly.
+ *
+ * For unit tests and similar cases where Spring Boot auto-configuration may not + * be active, loading of the agent can be triggered manually via + * {@link #enable()}. + */ +@Configuration +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +@ConditionalOnClass(AgentLoader.class) +public class EbeanAgentAutoConfiguration implements BeanFactoryPostProcessor, PriorityOrdered { + + public EbeanAgentAutoConfiguration() { + load(); // Spring has already evaluated the @ConditionalOnClass + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + // We're not actually doing anything with the BeanFactory, but implementing + // BeanFactoryPostProcessor ensures we get instantiated early, ideally + // before anybody has a chance to load any entity classes we want to + // enhance. + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + private static void load() { + AgentLoader.loadAgentFromClasspath("ebean-agent", "debug=1"); + } + + /** + * Loads the Ebean agent if the agent-loader and the agent itself are present + * on the classpath, or does nothing otherwise. + *
+ * Do not call this method from a static initializer as this can lead to a JVM
+ * deadlock (the agent attach thread will attempt to acquire the class loader
+ * lock, which is held during static initialization).
+ */
+ public static void enable() {
+ try {
+ load();
+ } catch (NoClassDefFoundError e) {
+ /* ignored */
+ }
+ }
+}
diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..d4fedf3b0
--- /dev/null
+++ b/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+io.ebean.spring.boot.EbeanAgentAutoConfiguration
diff --git a/src/test/java/io/ebean/spring/boot/EbeanAgentAutoConfigurationTest.java b/src/test/java/io/ebean/spring/boot/EbeanAgentAutoConfigurationTest.java
new file mode 100644
index 000000000..bbd7bc81e
--- /dev/null
+++ b/src/test/java/io/ebean/spring/boot/EbeanAgentAutoConfigurationTest.java
@@ -0,0 +1,35 @@
+package io.ebean.spring.boot;
+
+import io.ebean.bean.EntityBean;
+import org.junit.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.unenhanced.Boondoggle;
+import org.unenhanced.Wotsit;
+import static org.assertj.core.api.StrictAssertions.assertThat;
+
+@SpringBootTest(webEnvironment=WebEnvironment.NONE)
+public class EbeanAgentAutoConfigurationTest extends AbstractJUnit4SpringContextTests {
+
+ static {
+ // Validate our test setup. Agent should not be loaded yet, so 'Boondoggle'
+ // should have been enhanced neither at build time nor at load time.
+ assertThat(EntityBean.class.isAssignableFrom(Boondoggle.class)).isFalse();
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class Config {
+ /* no beans needed for this test */
+ }
+
+ @Test
+ public void testAgentIsWorking() {
+ // Wotsit is outside of the org.example package that's being enhanced
+ // at build time, so should be picked up by the agent only.
+ assertThat(EntityBean.class.isAssignableFrom(Wotsit.class)).isTrue();
+ }
+}
diff --git a/src/test/java/org/unenhanced/Boondoggle.java b/src/test/java/org/unenhanced/Boondoggle.java
new file mode 100644
index 000000000..0d23f258d
--- /dev/null
+++ b/src/test/java/org/unenhanced/Boondoggle.java
@@ -0,0 +1,11 @@
+package org.unenhanced;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+// Not in org.example, i.e. not enhanced at build time
+@Entity
+public class Boondoggle {
+ @Id
+ public String name;
+}
diff --git a/src/test/java/org/unenhanced/Wotsit.java b/src/test/java/org/unenhanced/Wotsit.java
new file mode 100644
index 000000000..e2e723caf
--- /dev/null
+++ b/src/test/java/org/unenhanced/Wotsit.java
@@ -0,0 +1,11 @@
+package org.unenhanced;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+// Not in org.example, i.e. not enhanced at build time
+@Entity
+public class Wotsit {
+ @Id
+ public String name;
+}
diff --git a/src/test/resources/init-database.xml b/src/test/resources/init-database.xml
index 2273a21f3..0ccf4cd6b 100644
--- a/src/test/resources/init-database.xml
+++ b/src/test/resources/init-database.xml
@@ -8,11 +8,6 @@
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
-
-
-
-
-