You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/01/12 14:35:33 UTC
[isis] branch master updated: ISIS-2033: adds support for injection
point resolving on JPA entities
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new 0c62ece ISIS-2033: adds support for injection point resolving on JPA entities
0c62ece is described below
commit 0c62ecec3ac4306d4f7ab7bc5e881946fab91873
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jan 12 15:35:16 2021 +0100
ISIS-2033: adds support for injection point resolving on JPA entities
---
.../commons/internal/exceptions/_Exceptions.java | 1 +
.../JpaEntityInjectionPointResolver.java | 73 +++++
.../jpa/eclipselink/IsisModuleJpaEclipseLink.java | 9 +-
.../inject/BeanManagerForEntityListeners.java | 327 +++++++++++++++++++++
.../persistence/jpa/eclipselink/inject/_Util.java | 157 ++++++++++
.../testdomain/conf/Configuration_usingJpa.java | 4 +
.../isis/testdomain/jpa/entities/JpaBook.java | 27 ++
.../isis/testdomain/jpa/entities/JpaInventory.java | 1 -
.../injecting/jpa/JpaEntityInjectingTest.java | 148 ++++++++++
.../wrapper/jdo/isis/JdoIsisWrapperSyncTest.java | 4 +-
10 files changed, 746 insertions(+), 5 deletions(-)
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/exceptions/_Exceptions.java b/commons/src/main/java/org/apache/isis/commons/internal/exceptions/_Exceptions.java
index 51c5d07..139a3ab 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/exceptions/_Exceptions.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/exceptions/_Exceptions.java
@@ -225,6 +225,7 @@ public final class _Exceptions {
*
*/
public static void throwNotImplemented() {
+ dumpStackTrace();
throw notImplemented();
}
diff --git a/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/integration/JpaEntityInjectionPointResolver.java b/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/integration/JpaEntityInjectionPointResolver.java
new file mode 100644
index 0000000..5bbc698
--- /dev/null
+++ b/persistence/jpa/applib/src/main/java/org/apache/isis/persistence/jpa/applib/integration/JpaEntityInjectionPointResolver.java
@@ -0,0 +1,73 @@
+/*
+ * 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.isis.persistence.jpa.applib.integration;
+
+import javax.inject.Inject;
+import javax.persistence.PostLoad;
+import javax.persistence.PostPersist;
+import javax.persistence.PostRemove;
+import javax.persistence.PostUpdate;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+
+import org.apache.isis.applib.services.inject.ServiceInjector;
+
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * EntityListener class for listing with the {@link javax.persistence.EntityListeners} annotation, to
+ * support injection point resolving for entities.
+ * <p>
+ * Instances of this class are not managed by Spring, but by the persistence layer.
+ * <p>
+ * The particular persistence layer implementation in use needs to be configured,
+ * with a BeanManager, that is able to resolve injection points for this EntityListener.
+ *
+ * @since 2.0
+ */
+@Log4j2
+public class JpaEntityInjectionPointResolver {
+
+ @Inject // not managed by Spring (directly)
+ private ServiceInjector serviceInjector;
+
+ @PrePersist
+ @PreUpdate
+ @PreRemove
+ private void beforeAnyUpdate(Object entityPojo) {
+ log.debug("beforeAnyUpdate: {}", entityPojo);
+ serviceInjector.injectServicesInto(entityPojo);
+ }
+
+ @PostPersist
+ @PostUpdate
+ @PostRemove
+ private void afterAnyUpdate(Object entityPojo) {
+ log.debug("afterAnyUpdate: {}" + entityPojo);
+ //serviceInjector.injectServicesInto(entityPojo);
+ }
+
+ @PostLoad
+ private void afterLoad(Object entityPojo) {
+ log.debug("afterLoad: {}" + entityPojo);
+ serviceInjector.injectServicesInto(entityPojo);
+ }
+
+}
diff --git a/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/IsisModuleJpaEclipseLink.java b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/IsisModuleJpaEclipseLink.java
index 144ad30..c8c3f0d 100644
--- a/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/IsisModuleJpaEclipseLink.java
+++ b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/IsisModuleJpaEclipseLink.java
@@ -21,6 +21,8 @@ package org.apache.isis.persistence.jpa.eclipselink;
import java.util.HashMap;
import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Provider;
import javax.sql.DataSource;
import org.eclipse.persistence.config.PersistenceUnitProperties;
@@ -33,6 +35,8 @@ import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
+import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.persistence.jpa.eclipselink.inject.BeanManagerForEntityListeners;
import org.apache.isis.persistence.jpa.integration.IsisModuleJpaIntegration;
/**
@@ -47,6 +51,8 @@ import org.apache.isis.persistence.jpa.integration.IsisModuleJpaIntegration;
})
public class IsisModuleJpaEclipseLink extends JpaBaseConfiguration {
+ @Inject private Provider<ServiceInjector> serviceInjectorProvider;
+
protected IsisModuleJpaEclipseLink(
DataSource dataSource,
JpaProperties properties,
@@ -59,12 +65,13 @@ public class IsisModuleJpaEclipseLink extends JpaBaseConfiguration {
return new EclipseLinkJpaVendorAdapter();
}
- //TODO[2033] this is application specific configuration that belongs to application.yaml
+ //TODO[2033] partly application specific configuration that belongs to application.yaml
@Override
protected Map<String, Object> getVendorProperties() {
HashMap<String, Object> map = new HashMap<>();
map.put(PersistenceUnitProperties.WEAVING, "false");
map.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.DROP_AND_CREATE);
+ map.put(PersistenceUnitProperties.CDI_BEANMANAGER, new BeanManagerForEntityListeners(serviceInjectorProvider));
return map;
}
diff --git a/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/BeanManagerForEntityListeners.java b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/BeanManagerForEntityListeners.java
new file mode 100644
index 0000000..c131e1a
--- /dev/null
+++ b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/BeanManagerForEntityListeners.java
@@ -0,0 +1,327 @@
+/*
+ * 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.isis.persistence.jpa.eclipselink.inject;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Set;
+
+import javax.el.ELResolver;
+import javax.el.ExpressionFactory;
+import javax.enterprise.context.spi.Context;
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Event;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMember;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanAttributes;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Decorator;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.InjectionTargetFactory;
+import javax.enterprise.inject.spi.InterceptionFactory;
+import javax.enterprise.inject.spi.InterceptionType;
+import javax.enterprise.inject.spi.Interceptor;
+import javax.enterprise.inject.spi.ObserverMethod;
+import javax.enterprise.inject.spi.ProducerFactory;
+import javax.inject.Provider;
+
+import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Incomplete implementation of a {@link BeanManager}, solely for the purpose of enabling
+ * injection point resolving on javax.persistence.EntityListeners.
+ * <p>
+ * Classes listed with the {@link javax.persistence.EntityListeners} annotation are not managed
+ * by Spring, hence injection point resolving for these is not supported out of the box. However,
+ * EclipseLink allows to configure a {@link BeanManager}, that is used for injection point
+ * resolving. This implementation is limited to support only no-arg constructors.
+ *
+ * @since 2.0
+ */
+@RequiredArgsConstructor
+public class BeanManagerForEntityListeners implements BeanManager {
+
+ private final Provider<ServiceInjector> serviceInjectorProvider;
+
+ @Override
+ public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual) {
+ return _Util.createCreationalContext(contextual);
+ }
+
+ @Override
+ public <T> AnnotatedType<T> createAnnotatedType(Class<T> type) {
+ return _Util.createAnnotatedType(type);
+ }
+
+ @Override
+ public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type) {
+ return _Util.createInjectionTarget(type, serviceInjectorProvider);
+ }
+
+ // -- IGNORED
+
+ @Override
+ public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<Bean<?>> getBeans(String name) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Bean<?> getPassivationCapableBean(String id) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public void validate(InjectionPoint injectionPoint) {
+ _Exceptions.throwNotImplemented();
+ }
+
+ @Override
+ public void fireEvent(Object event, Annotation... qualifiers) {
+ _Exceptions.throwNotImplemented();
+ }
+
+ @Override
+ public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... qualifiers) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public boolean isScope(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean isNormalScope(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean isPassivatingScope(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean isQualifier(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean isInterceptorBinding(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean isStereotype(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> bindingType) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public boolean areQualifiersEquivalent(Annotation qualifier1, Annotation qualifier2) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public boolean areInterceptorBindingsEquivalent(Annotation interceptorBinding1,
+ Annotation interceptorBinding2) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public int getQualifierHashCode(Annotation qualifier) {
+ _Exceptions.throwNotImplemented();
+ return 0;
+ }
+
+ @Override
+ public int getInterceptorBindingHashCode(Annotation interceptorBinding) {
+ _Exceptions.throwNotImplemented();
+ return 0;
+ }
+
+ @Override
+ public Context getContext(Class<? extends Annotation> scopeType) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public ELResolver getELResolver() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T> InjectionTargetFactory<T> getInjectionTargetFactory(AnnotatedType<T> annotatedType) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <X> ProducerFactory<X> getProducerFactory(AnnotatedField<? super X> field, Bean<X> declaringBean) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <X> ProducerFactory<X> getProducerFactory(AnnotatedMethod<? super X> method, Bean<X> declaringBean) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> type) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<T> beanClass,
+ InjectionTargetFactory<T> injectionTargetFactory) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T, X> Bean<T> createBean(BeanAttributes<T> attributes, Class<X> beanClass,
+ ProducerFactory<X> producerFactory) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public InjectionPoint createInjectionPoint(AnnotatedField<?> field) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public InjectionPoint createInjectionPoint(AnnotatedParameter<?> parameter) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T extends Extension> T getExtension(Class<T> extensionClass) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <T> InterceptionFactory<T> createInterceptionFactory(CreationalContext<T> ctx, Class<T> clazz) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Event<Object> getEvent() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Instance<Object> createInstance() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+
+}
diff --git a/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/_Util.java b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/_Util.java
new file mode 100644
index 0000000..ce9fbdd
--- /dev/null
+++ b/persistence/jpa/eclipselink/src/main/java/org/apache/isis/persistence/jpa/eclipselink/inject/_Util.java
@@ -0,0 +1,157 @@
+/*
+ * 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.isis.persistence.jpa.eclipselink.inject;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.inject.Provider;
+
+import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.SneakyThrows;
+
+final class _Util {
+
+ static <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual) {
+ return new CreationalContext<T>() {
+
+ @Override
+ public void push(T incompleteInstance) {
+ // silently ignore
+ }
+
+ @Override
+ public void release() {
+ // silently ignore
+ }
+
+ };
+ }
+
+ static <T> AnnotatedType<T> createAnnotatedType(Class<T> type) {
+
+ return new AnnotatedType<T>() {
+
+ @Override
+ public Class<T> getJavaClass() {
+ return type;
+ }
+
+ @Override
+ public Type getBaseType() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<Type> getTypeClosure() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public <X extends Annotation> X getAnnotation(Class<X> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<Annotation> getAnnotations() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+ _Exceptions.throwNotImplemented();
+ return false;
+ }
+
+ @Override
+ public Set<AnnotatedConstructor<T>> getConstructors() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<AnnotatedMethod<? super T>> getMethods() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+
+ @Override
+ public Set<AnnotatedField<? super T>> getFields() {
+ _Exceptions.throwNotImplemented();
+ return null;
+ }
+ };
+ }
+
+ static <T> InjectionTarget<T> createInjectionTarget(
+ final AnnotatedType<T> type,
+ final Provider<ServiceInjector> serviceInjectorProvider) {
+
+ return new InjectionTarget<T>() {
+
+ @Override @SneakyThrows
+ public T produce(CreationalContext<T> ctx) {
+ return type.getJavaClass().newInstance();
+ }
+
+ @Override
+ public void inject(T instance, CreationalContext<T> ctx) {
+ serviceInjectorProvider.get().injectServicesInto(instance);
+ }
+
+ @Override
+ public void dispose(T instance) {
+ // silently ignore
+ }
+
+ @Override
+ public Set<InjectionPoint> getInjectionPoints() {
+ // silently ignore
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void postConstruct(T instance) {
+ // silently ignore
+ }
+
+ @Override
+ public void preDestroy(T instance) {
+ // silently ignore
+ }
+ };
+ }
+
+}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_usingJpa.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_usingJpa.java
index 27719e1..92b0d97f 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_usingJpa.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_usingJpa.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
import org.apache.isis.persistence.jpa.eclipselink.IsisModuleJpaEclipseLink;
import org.apache.isis.security.bypass.IsisModuleSecurityBypass;
import org.apache.isis.testdomain.jpa.JpaTestDomainModule;
+import org.apache.isis.testdomain.model.stereotypes.MyService;
import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
import org.apache.isis.testing.fixtures.applib.IsisModuleTestingFixturesApplib;
@@ -40,6 +41,9 @@ import org.apache.isis.testing.fixtures.applib.IsisModuleTestingFixturesApplib;
//@Configuration
@Import({
+
+ MyService.class, // testing injection into entities
+
IsisModuleCoreRuntimeServices.class
,IsisModuleSecurityBypass.class
,IsisModuleJpaEclipseLink.class
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaBook.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaBook.java
index e1f7c75..f3db754 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaBook.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaBook.java
@@ -18,22 +18,31 @@
*/
package org.apache.isis.testdomain.jpa.entities;
+import javax.inject.Inject;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.Transient;
import org.apache.isis.applib.annotation.DomainObject;
import org.apache.isis.applib.annotation.Nature;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.Publishing;
+import org.apache.isis.persistence.jpa.applib.integration.JpaEntityInjectionPointResolver;
+import org.apache.isis.testdomain.model.stereotypes.MyService;
+import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
@Entity
+@EntityListeners(JpaEntityInjectionPointResolver.class)
@DiscriminatorValue("Book")
@DomainObject(
objectType = "testdomain.jpa.Book",
@@ -41,8 +50,25 @@ import lombok.ToString;
entityChangePublishing = Publishing.ENABLED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(callSuper = true)
+@Log4j2
public class JpaBook extends JpaProduct {
+ @Inject @Transient private KVStoreForTesting kvStore;
+
+ // -- ENTITY SERVICE INJECTION TEST
+ @Transient private MyService myService;
+ @Inject
+ public void setMyService(MyService myService) {
+ val count = kvStore.incrementCounter(JpaBook.class, "injection-count");
+ log.debug("INJECTION " + count);
+ this.myService = myService;
+ }
+ public boolean hasInjectionPointsResolved() {
+ getAuthor(); // seems to have the required side-effect to actually trigger injection
+ return myService != null;
+ }
+ // --
+
@Override
public String title() {
return toString();
@@ -86,4 +112,5 @@ public class JpaBook extends JpaProduct {
this.isbn = isbn;
this.publisher = publisher;
}
+
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
index 72edde8..cc101b3 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
@@ -30,7 +30,6 @@ import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import org.apache.isis.applib.annotation.DomainObject;
-import org.apache.isis.applib.annotation.DomainObjectLayout;
import org.apache.isis.applib.annotation.Nature;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.Publishing;
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/injecting/jpa/JpaEntityInjectingTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/injecting/jpa/JpaEntityInjectingTest.java
new file mode 100644
index 0000000..b36d13a
--- /dev/null
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/injecting/jpa/JpaEntityInjectingTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.isis.testdomain.injecting.jpa;
+
+import javax.inject.Inject;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.isis.applib.services.repository.RepositoryService;
+import org.apache.isis.commons.internal.assertions._Assert;
+import org.apache.isis.commons.internal.primitives._Longs.Bound;
+import org.apache.isis.commons.internal.primitives._Longs.Range;
+import org.apache.isis.core.config.presets.IsisPresets;
+import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.jpa.JpaTestDomainPersona;
+import org.apache.isis.testdomain.jpa.entities.JpaBook;
+import org.apache.isis.testdomain.jpa.entities.JpaProduct;
+import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
+import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
+import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
+
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@SpringBootTest(
+ classes = {
+ Configuration_usingJpa.class
+ },
+ properties = {
+// "logging.level.org.apache.isis.persistence.jdo.integration.changetracking.JdoLifecycleListener=DEBUG",
+// "logging.level.org.apache.isis.testdomain.injecting.jdo.isis.JdoIsisEntityInjectingTest=DEBUG"
+ }
+)
+@TestPropertySource(IsisPresets.UseLog4j2Test)
+@Transactional
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@Log4j2
+class JpaEntityInjectingTest extends IsisIntegrationTestAbstract {
+
+ @Inject private FixtureScripts fixtureScripts;
+ @Inject private RepositoryService repository;
+ @Inject private KVStoreForTesting kvStore;
+
+ @Test @Order(0) @Rollback(false)
+ void init() {
+
+ // cleanup
+ fixtureScripts.runPersona(JpaTestDomainPersona.PurgeAll);
+ kvStore.clear(JpaBook.class);
+
+ // given
+ fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
+ assertInjectCountRange(1, 2);
+ }
+
+
+ @Test @Order(1)
+ void sampleBook_shouldHave_injectionPointsResolved() {
+ log.debug("TEST 1 ENTERING");
+
+ //assertInjectCountRange(1, 2);
+
+ val book = getSampleBook();
+ assertTrue(book.hasInjectionPointsResolved());
+
+ //assertInjectCountRange(1, 3);
+
+ log.debug("TEST 1 EXITING");
+ }
+
+ @Test @Order(2)
+ void sampleBook_shouldHave_injectionPointsResolved_whenFetchedAgain() {
+
+ log.debug("TEST 2 ENTERING");
+
+ //assertInjectCountRange(1, 2);
+
+ val book = getSampleBook();
+ assertTrue(book.hasInjectionPointsResolved());
+
+ //assertInjectCountRange(1, 3);
+
+ log.debug("TEST 2 EXITING");
+
+ }
+
+ @Test @Order(3)
+ void sampleBook_shouldHave_injectionPointsResolved_whenFetchedAgain2() {
+
+ log.debug("TEST 3 ENTERING");
+
+ //assertInjectCountRange(1, 3);
+
+ val book = getSampleBook();
+ assertTrue(book.hasInjectionPointsResolved());
+
+ //assertInjectCountRange(1, 4);
+
+ log.debug("TEST 3 EXITING");
+ }
+
+ // -- HELPER
+
+ private long getInjectCount() {
+ return kvStore.getCounter(JpaBook.class, "injection-count");
+ }
+
+ private JpaBook getSampleBook() {
+ val books = repository.allInstances(JpaProduct.class);
+ assertEquals(1, books.size(), "book count");
+ val book = books.get(0);
+ assertEquals("Sample Book", book.getName(), "book name");
+ return (JpaBook)book;
+ }
+
+ private void assertInjectCountRange(long lower, long upper) {
+ _Assert.assertRangeContains(
+ Range.of(Bound.inclusive(lower), Bound.inclusive(upper)),
+ getInjectCount(), "injection count");
+ }
+
+}
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/wrapper/jdo/isis/JdoIsisWrapperSyncTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/wrapper/jdo/isis/JdoIsisWrapperSyncTest.java
index 16b74ac..9d4e1e4 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/wrapper/jdo/isis/JdoIsisWrapperSyncTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/wrapper/jdo/isis/JdoIsisWrapperSyncTest.java
@@ -23,7 +23,6 @@ import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
@@ -50,7 +49,6 @@ import lombok.val;
}
)
@TestPropertySource(IsisPresets.UseLog4j2Test)
-//@Incubating("wrapper.wrap(inventoryManager) throws NPE")
class JdoIsisWrapperSyncTest extends IsisIntegrationTestAbstract {
@Inject private FixtureScripts fixtureScripts;
@@ -67,7 +65,7 @@ class JdoIsisWrapperSyncTest extends IsisIntegrationTestAbstract {
fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
}
- @Test @Tag("Incubating")
+ @Test
void testWrapper_waitingOnDomainEvent() throws InterruptedException, ExecutionException {
val inventoryManager = facoryService.viewModel(JdoInventoryManager.class);