View difference between Paste ID: 8cPB96bZ and kesM4XJJ
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
}