2 * Copyright (C) 2018 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
9 package eu
.etaxonomy
.cdm
.model
;
11 import java
.lang
.reflect
.InvocationTargetException
;
12 import java
.lang
.reflect
.Method
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.List
;
17 import org
.apache
.commons
.lang3
.StringUtils
;
19 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
22 * In many cases the add*() and remove*() methods of entity classes contain important business
23 * logic which would be short-circuited if the set*() method would be public. This adapter allows
24 * providing setter methods to make the bean property writable.
26 * The {{@link #setCollection(CdmBase, Collection)} method uses the add*() and remove*() methods
27 * in order to update the collection field of the bean.
33 * private EntityCollectionSetterAdapter<Team, Person> teamMembersSetterAdapter = new EntityCollectionSetterAdapter<Team, Person>(Team.class, Person.class, "teamMembers");
35 * public void setTeamMembers(List<Person> teamMembers) throws SetterAdapterException {
36 * teamMembersSetterAdapter.setCollection(this, teamMembers);
40 * see https://dev.e-taxonomy.eu/redmine/issues/7600
42 * @author a.kohlbecker
46 public class EntityCollectionSetterAdapter
<CDM
extends CdmBase
, T
extends CdmBase
> {
48 private Class
<T
> propertyItemType
;
49 private Method getMethod
;
50 private Method addMethod
;
51 private Method removeMethod
;
52 private Exception getMethodException
;
53 private Exception addMethodException
;
54 private Exception removeMethodException
;
56 public EntityCollectionSetterAdapter(Class
<CDM
> beanClass
, Class
<T
> propertyItemType
, String propertyName
){
60 "add" + StringUtils
.capitalize(propertyName
.substring(0, propertyName
.length() - 1)),
61 "remove" + StringUtils
.capitalize(propertyName
.substring(0, propertyName
.length() - 1))
65 public EntityCollectionSetterAdapter(Class
<CDM
> beanClass
, Class
<T
> propertyItemType
, String propertyName
, String addMethodName
, String removMethodName
){
67 this.propertyItemType
= propertyItemType
;
69 getMethod
= beanClass
.getDeclaredMethod("get" + StringUtils
.capitalize(propertyName
));
70 } catch (NoSuchMethodException
| SecurityException e
) {
71 getMethodException
= e
;
74 addMethod
= beanClass
.getDeclaredMethod(addMethodName
, propertyItemType
);
75 } catch (NoSuchMethodException
| SecurityException e
) {
76 addMethodException
= e
;
79 removeMethod
= beanClass
.getDeclaredMethod(removMethodName
, propertyItemType
);
80 } catch (NoSuchMethodException
| SecurityException e
) {
81 removeMethodException
= e
;
85 public void setCollection(CDM bean
, Collection
<T
> items
) throws SetterAdapterException
{
87 if(getMethodException
!= null){
88 throw new SetterAdapterException("No getter method due to previous exception.", getMethodException
);
90 if(addMethodException
!= null){
91 throw new SetterAdapterException("No add method due to previous exception.", addMethodException
);
93 if(removeMethodException
!= null){
94 throw new SetterAdapterException("No remove method due to previous exception.", removeMethodException
);
98 Collection
<T
> getterCollection
= (Collection
<T
>) getMethod
.invoke(bean
);
99 List
<T
> currentItems
= new ArrayList
<>(getterCollection
);
100 List
<T
> itemsSeen
= new ArrayList
<>();
105 if(!currentItems
.contains(a
)){
106 addMethod
.invoke(bean
, a
);
110 for(T a
: currentItems
){
111 if(!itemsSeen
.contains(a
)){
112 removeMethod
.invoke(bean
, a
);
115 } catch(ClassCastException e
){
116 throw new SetterAdapterException("getter return type (" + getMethod
.getReturnType() + ") incompatible with expected property type " + propertyItemType
, e
);
117 } catch (IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e
) {
118 throw new SetterAdapterException("error invoking method", e
);
122 public static class SetterAdapterException
extends Exception
{
124 private static final long serialVersionUID
= 1L;
130 public SetterAdapterException(String message
, Throwable cause
) {
131 super(message
, cause
);