SHOW:
|
|
- or go back to the newest paste.
| 1 | @Target({
| |
| 2 | ElementType.TYPE, | |
| 3 | ElementType.METHOD, | |
| 4 | }) | |
| 5 | @Retention(RetentionPolicy.RUNTIME) | |
| 6 | public @interface PreCollectionChange {
| |
| 7 | } | |
| 8 | ||
| 9 | ||
| 10 | ||
| 11 | public class IntegratorImpl implements Integrator {
| |
| 12 | ||
| 13 | private final Map<Class<?>, List<Method>> preCollectionChangeMethods; | |
| 14 | ||
| 15 | public IntegratorImpl() {
| |
| 16 | this.preCollectionChangeMethods = new ConcurrentHashMap<>(); | |
| 17 | } | |
| 18 | ||
| 19 | @Override | |
| 20 | public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
| |
| 21 | EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class); | |
| 22 | registry.getEventListenerGroup(EventType.FLUSH_ENTITY).appendListener(new PreCollectionChangeFlushEntityEventListener()); | |
| 23 | } | |
| 24 | ||
| 25 | private class PreCollectionChangeFlushEntityEventListener implements FlushEntityEventListener {
| |
| 26 | ||
| 27 | @Override | |
| 28 | public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
| |
| 29 | Object entity = event.getEntity(); | |
| 30 | Class<?> entityClass = entity.getClass(); | |
| 31 | ||
| 32 | if (!preCollectionChangeMethods.containsKey(entityClass)) {
| |
| 33 | Method[] uniqueDeclaredMethods = ReflectionUtils.getUniqueDeclaredMethods(entityClass); | |
| 34 | List<Method> methods = Arrays.asList(uniqueDeclaredMethods).stream() | |
| 35 | .filter(method -> AnnotationUtils.findAnnotation(method, PreCollectionChange.class) != null) | |
| 36 | .map(method -> {
| |
| 37 | method.setAccessible(true); | |
| 38 | return method; | |
| 39 | }) | |
| 40 | .collect(Collectors.toList()); | |
| 41 | // Place leaf methods in the end to correspond to constructors order. | |
| 42 | Collections.reverse(methods); | |
| 43 | preCollectionChangeMethods.put(entityClass, methods); | |
| 44 | } | |
| 45 | ||
| 46 | List<Method> methods = preCollectionChangeMethods.get(entityClass); | |
| 47 | for (Method method : methods) {
| |
| 48 | try {
| |
| 49 | method.invoke(entity, (Object[]) null); | |
| 50 | } catch (IllegalAccessException | InvocationTargetException e) {
| |
| 51 | throw new CallbackException(e); | |
| 52 | } | |
| 53 | } | |
| 54 | } | |
| 55 | } | |
| 56 | } | |
| 57 | ||
| 58 | ||
| 59 | ||
| 60 | @Entity | |
| 61 | public abstract class Device {
| |
| 62 | ||
| 63 | @ManyToMany | |
| 64 | @JoinTable( | |
| 65 | name = "device_application", | |
| 66 | joinColumns = {
| |
| 67 | @JoinColumn(name = "device_id"), | |
| 68 | }, | |
| 69 | inverseJoinColumns = {
| |
| 70 | @JoinColumn(name = "application_id"), | |
| 71 | }) | |
| 72 | private Set<Application> applications = new HashSet<>(); | |
| 73 | ||
| 74 | public Set<Application> getApplications() {
| |
| 75 | return applications; | |
| 76 | } | |
| 77 | ||
| 78 | public void setApplications(Set<Application> applications) {
| |
| 79 | this.applications = applications; | |
| 80 | } | |
| 81 | ||
| 82 | @PrePersist | |
| 83 | private void prePersist() {
| |
| 84 | checkApplications(); | |
| 85 | } | |
| 86 | ||
| 87 | @PreUpdate | |
| 88 | private void preUpdate() {
| |
| 89 | checkApplications(); | |
| 90 | } | |
| 91 | ||
| 92 | @PreCollectionChange | |
| 93 | private void checkApplications() {
| |
| 94 | Class<? extends Application> applicationClass = getApplicationClass(); | |
| 95 | for (Application application : applications) {
| |
| 96 | if (!applicationClass.isAssignableFrom(application.getClass())) {
| |
| 97 | throw new IllegalStateException("All applications must be of class " + applicationClass.getName());
| |
| 98 | } | |
| 99 | } | |
| 100 | } | |
| 101 | ||
| 102 | @Transient | |
| 103 | protected abstract Class<? extends Application> getApplicationClass(); | |
| 104 | } |