Skip to content

Commit 1cfceda

Browse files
chore: merge release-1.x into dev-1.x [skip ci]
2 parents 6ee9316 + 6b17122 commit 1cfceda

17 files changed

Lines changed: 906 additions & 6 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ pom.xml:
4444

4545
| **Branches** | **Purpose** | **Latest Version** |
4646
|--------------|--------------------------------------------------|--------------------|
47-
| **0.2.x** | Compatible with Spring Cloud 2022.0.x - 2025.0.x | 0.2.0 |
48-
| **0.1.x** | Compatible with Spring Cloud Hoxton - 2021.0.x | 0.1.0 |
47+
| **main** | Compatible with Spring Cloud 2022.0.x - 2025.0.x | 0.2.1 |
48+
| **1.x** | Compatible with Spring Cloud Hoxton - 2021.0.x | 0.1.1 |
4949

5050
### Compatibility
5151

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/DelegatingInterceptor.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@
3232
/**
3333
* Delegating {@link Interceptor}
3434
*
35+
* <h3>Example Usage</h3>
36+
* <pre>{@code
37+
* // Wrap a custom Interceptor to extend it
38+
* Interceptor myInterceptor = new EmptyInterceptor() {
39+
* @Override
40+
* public boolean onLoad(Object entity, Object id, Object[] state,
41+
* String[] propertyNames, Type[] types) {
42+
* System.out.println("Loading entity: " + entity);
43+
* return false;
44+
* }
45+
* };
46+
* DelegatingInterceptor interceptor = new DelegatingInterceptor(myInterceptor);
47+
*
48+
* // Pass null to fall back to EmptyInterceptor.INSTANCE
49+
* DelegatingInterceptor defaultInterceptor = new DelegatingInterceptor(null);
50+
* }</pre>
51+
*
3552
* @author <a href="mailto:mercyblitz@gmail.com">Mercy<a/>
3653
* @see Interceptor
3754
* @since 1.0.0
@@ -40,6 +57,12 @@ public class DelegatingInterceptor implements Interceptor, DelegatingWrapper {
4057

4158
protected final Interceptor delegate;
4259

60+
/**
61+
* Creates a new {@link DelegatingInterceptor} wrapping the given delegate.
62+
* If {@code delegate} is {@code null}, {@link org.hibernate.internal.EmptyInterceptor#INSTANCE} is used.
63+
*
64+
* @param delegate the {@link Interceptor} to delegate to, or {@code null} for the empty interceptor
65+
*/
4366
public DelegatingInterceptor(@Nullable Interceptor delegate) {
4467
this.delegate = delegate == null ? INSTANCE : delegate;
4568
}

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/constants/PropertyConstants.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@
2828
/**
2929
* The interface to declare the property constants of Microsphere Hibernate
3030
*
31+
* <h3>Example Usage</h3>
32+
* <pre>{@code
33+
* // Enable Microsphere Hibernate via system property
34+
* System.setProperty(MICROSPHERE_HIBERNATE_ENABLED_PROPERTY_NAME, "true");
35+
*
36+
* // Read the enabled flag
37+
* boolean enabled = Boolean.parseBoolean(
38+
* System.getProperty(MICROSPHERE_HIBERNATE_ENABLED_PROPERTY_NAME,
39+
* DEFAULT_MICROSPHERE_HIBERNATE_ENABLED_PROPERTY_VALUE));
40+
*
41+
* // Use the property name prefix to build custom property names
42+
* String customProperty = MICROSPHERE_HIBERNATE_PROPERTY_NAME_PREFIX + "myFeature.enabled";
43+
* }</pre>
44+
*
3145
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
3246
* @since 1.0.0
3347
*/

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/entity/CompositeEntityCallback.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929
/**
3030
* Composite {@link EntityCallback}
3131
*
32+
* <h3>Example Usage</h3>
33+
* <pre>{@code
34+
* EntityCallback loggingCallback = new LoggingEntityCallback();
35+
* EntityCallback auditCallback = new AuditEntityCallback();
36+
* List<EntityCallback> callbacks = Arrays.asList(loggingCallback, auditCallback);
37+
* CompositeEntityCallback composite = new CompositeEntityCallback(callbacks);
38+
*
39+
* // The composite will invoke both callbacks in order
40+
* composite.onPersist(myEntity, "MyEntity");
41+
* composite.onLoad(entityId, "MyEntity", myEntity, LockMode.NONE,
42+
* false, null, null, LoadType.GET);
43+
* }</pre>
44+
*
3245
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
3346
* @see EntityCallback
3447
* @since 1.0.0
@@ -37,6 +50,12 @@ public class CompositeEntityCallback implements EntityCallback {
3750

3851
private final List<EntityCallback> callbacks;
3952

53+
/**
54+
* Creates a new {@link CompositeEntityCallback} backed by the given list of callbacks.
55+
* Each callback will be invoked in the order it appears in the list.
56+
*
57+
* @param callbacks the ordered list of {@link EntityCallback} instances to delegate to
58+
*/
4059
public CompositeEntityCallback(List<EntityCallback> callbacks) {
4160
this.callbacks = callbacks;
4261
}

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/entity/EntittyCallbackIntegrator.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@
5151
/**
5252
* Hibernate {@link Integrator} for {@link EntityCallback}
5353
*
54+
* <h3>Example Usage</h3>
55+
* <pre>{@code
56+
* // Register via META-INF/services/org.hibernate.integrator.spi.Integrator
57+
* // (file content: io.microsphere.hibernate.entity.EntittyCallbackIntegrator)
58+
*
59+
* // Or register programmatically when building the SessionFactory:
60+
* Configuration configuration = new Configuration()
61+
* .addAnnotatedClass(User.class);
62+
* SessionFactory sessionFactory = configuration
63+
* .buildSessionFactory(
64+
* new StandardServiceRegistryBuilder()
65+
* .applySettings(configuration.getProperties())
66+
* .build()
67+
* );
68+
*
69+
* // Once active, all EntityCallback implementations loaded via ServiceLoader
70+
* // are notified for Hibernate events (load, persist, delete, merge, etc.)
71+
* }</pre>
72+
*
5473
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
5574
* @see Integrator
5675
* @see DuplicationStrategy
@@ -59,6 +78,14 @@
5978
*/
6079
public class EntittyCallbackIntegrator implements Integrator {
6180

81+
/**
82+
* Registers the {@link EntityCallbackListener} for all supported Hibernate event types
83+
* on the given {@link SessionFactoryImplementor}.
84+
*
85+
* @param metadata the Hibernate metadata
86+
* @param sessionFactory the session factory being built
87+
* @param serviceRegistry the session factory service registry
88+
*/
6289
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
6390
EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
6491

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/entity/EntityCallback.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,32 @@
5757
* The lifecycle callback interface for entity.
5858
* The implementation class will be loaded by {@link ServiceLoader Java Services Loader}.
5959
*
60+
* <h3>Example Usage</h3>
61+
* <pre>{@code
62+
* // Implement a custom EntityCallback registered via
63+
* // META-INF/services/io.microsphere.hibernate.entity.EntityCallback
64+
* public class LoggingEntityCallback implements EntityCallback {
65+
*
66+
* @Override
67+
* public void onPersist(Object entity, String entityName) {
68+
* System.out.println("Persisting: " + entityName + " -> " + entity);
69+
* }
70+
*
71+
* @Override
72+
* public void onLoad(Object id, String entityClassName, Object entity,
73+
* LockMode lockMode, boolean isAssociationFetch,
74+
* Object result, Boolean readOnly, LoadType loadType) {
75+
* System.out.println("Loading: " + entityClassName + " id=" + id);
76+
* }
77+
*
78+
* @Override
79+
* public void onPreDelete(Object entity, Object id, Object[] state,
80+
* String[] propertyNames, Type[] types) {
81+
* System.out.println("About to delete: " + entity);
82+
* }
83+
* }
84+
* }</pre>
85+
*
6086
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
6187
* @see LoadEventListener
6288
* @see PersistEventListener

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/entity/EntityCallbackListener.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,19 @@
8282
/**
8383
* The listener class for {@link EntityCallback}
8484
*
85+
* <h3>Example Usage</h3>
86+
* <pre>{@code
87+
* // Default constructor loads EntityCallback implementations via ServiceLoader
88+
* EntityCallbackListener listener = new EntityCallbackListener();
89+
*
90+
* // Or supply callbacks directly (useful in tests)
91+
* List<EntityCallback> callbacks = Arrays.asList(new LoggingEntityCallback());
92+
* EntityCallbackListener listener = new EntityCallbackListener(callbacks);
93+
*
94+
* // The listener is registered by {@link EntittyCallbackIntegrator} on SessionFactory startup;
95+
* // it translates Hibernate events into EntityCallback invocations automatically.
96+
* }</pre>
97+
*
8598
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
8699
* @see LoadEventListener
87100
* @see PersistEventListener
@@ -123,10 +136,20 @@ class EntityCallbackListener implements LoadEventListener, PersistEventListener,
123136

124137
private final EntityCallback callback;
125138

139+
/**
140+
* Creates a new {@link EntityCallbackListener} that loads {@link EntityCallback} implementations
141+
* from the classpath using {@link java.util.ServiceLoader}.
142+
*/
126143
EntityCallbackListener() {
127144
this(load(EntityCallback.class));
128145
}
129146

147+
/**
148+
* Creates a new {@link EntityCallbackListener} backed by the given {@link EntityCallback} instances.
149+
* Callbacks are sorted by priority using {@link io.microsphere.lang.Prioritized#COMPARATOR}.
150+
*
151+
* @param callbacks the iterable of {@link EntityCallback} instances to use
152+
*/
130153
EntityCallbackListener(Iterable<EntityCallback> callbacks) {
131154
List<EntityCallback> entityCallbacks = newLinkedList(callbacks);
132155
entityCallbacks.sort(COMPARATOR);
@@ -342,6 +365,12 @@ public boolean requiresPostCommitHandling(EntityPersister persister) {
342365
return PostDeleteEventListener.super.requiresPostCommitHandling(persister);
343366
}
344367

368+
/**
369+
* Extracts the {@link LockMode} from the given {@link LockOptions}.
370+
*
371+
* @param lockOptions the lock options to extract the lock mode from
372+
* @return the {@link LockMode} from the given {@link LockOptions}
373+
*/
345374
protected LockMode getLockMode(LockOptions lockOptions) {
346375
return lockOptions.getLockMode();
347376
}

microsphere-hibernate-core/src/main/java/io/microsphere/hibernate/entity/EntityCallbackListenerDuplicationStrategy.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,45 @@
2626
/**
2727
* {@link DuplicationStrategy} class for {@link EntityCallbackListener}
2828
*
29+
* <h3>Example Usage</h3>
30+
* <pre>{@code
31+
* // Used internally by EntittyCallbackIntegrator to prevent duplicate listener registration
32+
* EntityCallbackListenerDuplicationStrategy strategy = new EntityCallbackListenerDuplicationStrategy();
33+
*
34+
* EntityCallbackListener listener1 = new EntityCallbackListener();
35+
* EntityCallbackListener listener2 = new EntityCallbackListener();
36+
* boolean match = strategy.areMatch(listener1, listener2); // true — same class
37+
*
38+
* DuplicationStrategy.Action action = strategy.getAction(); // KEEP_ORIGINAL
39+
* }</pre>
40+
*
2941
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
3042
* @see EntityCallbackListener
3143
* @since 1.0.0
3244
*/
3345
class EntityCallbackListenerDuplicationStrategy implements DuplicationStrategy {
3446

47+
/**
48+
* Returns {@code true} if both {@code listener} and {@code original} are instances of
49+
* {@link EntityCallbackListener}, preventing duplicate registrations.
50+
*
51+
* @param listener the candidate listener
52+
* @param original the already-registered listener
53+
* @return {@code true} if both are instances of {@link EntityCallbackListener}
54+
*/
3555
@Override
3656
public boolean areMatch(Object listener, Object original) {
3757
Class<?> listenerClass = listener.getClass();
3858
return Objects.equals(listenerClass, original.getClass())
3959
&& EntityCallbackListener.class.equals(listenerClass);
4060
}
4161

62+
/**
63+
* Returns {@link org.hibernate.event.service.spi.DuplicationStrategy.Action#KEEP_ORIGINAL},
64+
* meaning the first registered {@link EntityCallbackListener} is retained when a duplicate is detected.
65+
*
66+
* @return {@link org.hibernate.event.service.spi.DuplicationStrategy.Action#KEEP_ORIGINAL}
67+
*/
4268
@Override
4369
public Action getAction() {
4470
return KEEP_ORIGINAL;

microsphere-hibernate-parent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<description>Microsphere Hibernate Parent</description>
2020

2121
<properties>
22-
<microsphere-spring-cloud.version>0.1.11</microsphere-spring-cloud.version>
22+
<microsphere-spring-cloud.version>0.1.12</microsphere-spring-cloud.version>
2323
</properties>
2424

2525
<dependencyManagement>

microsphere-hibernate-test/src/main/java/io/microsphere/hibernate/test/AbstractHibernateH2Test.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,30 @@
4040
/**
4141
* Abstract Hibernate Test for H2 Database
4242
*
43+
* <h3>Example Usage</h3>
44+
* <pre>{@code
45+
* // Extend to write Hibernate integration tests backed by an in-memory H2 database
46+
* class MyEntityTest extends AbstractHibernateH2Test {
47+
*
48+
* @Test
49+
* void testPersistAndGet() {
50+
* doInTransaction(() -> {
51+
* session.persist(user);
52+
* User found = session.get(User.class, user.getId());
53+
* assertEquals(user, found);
54+
* });
55+
* }
56+
*
57+
* // Override createUser() to provide a custom User graph for tests
58+
* @Override
59+
* protected User createUser() {
60+
* User user = new User();
61+
* user.setName("Alice");
62+
* return user;
63+
* }
64+
* }
65+
* }</pre>
66+
*
4367
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
4468
* @see AbstractHibernateTest
4569
* @since 1.0.0
@@ -54,6 +78,12 @@ protected void init() {
5478
user = createUser();
5579
}
5680

81+
/**
82+
* Creates a default {@link User} entity graph (with {@link UserProfile}, {@link Order}, and
83+
* {@link Product}) used as test fixture data. Override to supply a custom graph.
84+
*
85+
* @return a new {@link User} instance with associated entities
86+
*/
5787
protected User createUser() {
5888
User user = new User();
5989
user.setName("Tom");
@@ -92,6 +122,11 @@ protected Configuration buildConfiguration() {
92122
return configuration;
93123
}
94124

125+
/**
126+
* Executes the given action, asserting that it completes without throwing any exception.
127+
*
128+
* @param action the action to run
129+
*/
95130
protected void doInAction(Runnable action) {
96131
assertDoesNotThrow(action::run);
97132
}

0 commit comments

Comments
 (0)