|  | 
| 35 | 35 | import de.danielbechler.diff.selector.BeanPropertyElementSelector; | 
| 36 | 36 | import de.danielbechler.util.Assert; | 
| 37 | 37 | 
 | 
| 38 |  | -public class PropertyAccessor implements PropertyAwareAccessor { | 
| 39 |  | -   private static final Logger logger = LoggerFactory.getLogger(PropertyAccessor.class); | 
|  | 38 | +public class PropertyAccessor implements PropertyAwareAccessor | 
|  | 39 | +{ | 
|  | 40 | +	private static final Logger logger = LoggerFactory.getLogger(PropertyAccessor.class); | 
| 40 | 41 | 
 | 
| 41 |  | -   private final String propertyName; | 
| 42 |  | -   private final Class<?> type; | 
| 43 |  | -   private final Method readMethod; | 
| 44 |  | -   private final Method writeMethod; | 
|  | 42 | +	private final String propertyName; | 
|  | 43 | +	private final Class<?> type; | 
|  | 44 | +	private final Method readMethod; | 
|  | 45 | +	private final Method writeMethod; | 
| 45 | 46 |    private final Field field; | 
| 46 | 47 | 
 | 
| 47 |  | -   public PropertyAccessor(final String propertyName, final Field f, final Method readMethod, final Method writeMethod) { | 
| 48 |  | -      Assert.notNull(propertyName, "propertyName"); | 
| 49 |  | -      Assert.notNull(readMethod, "readMethod"); | 
| 50 |  | -      this.propertyName = propertyName; | 
|  | 48 | +	public PropertyAccessor(final String propertyName, final Field f, final Method readMethod, final Method writeMethod) | 
|  | 49 | +	{ | 
|  | 50 | +		Assert.notNull(propertyName, "propertyName"); | 
|  | 51 | +		Assert.notNull(readMethod, "readMethod"); | 
|  | 52 | +		this.propertyName = propertyName; | 
| 51 | 53 |       this.field = f; | 
| 52 |  | -      this.readMethod = makeAccessible(readMethod); | 
| 53 |  | -      this.writeMethod = makeAccessible(writeMethod); | 
| 54 |  | -      this.type = this.readMethod.getReturnType(); | 
| 55 |  | -   } | 
|  | 54 | +		this.readMethod = makeAccessible(readMethod); | 
|  | 55 | +		this.writeMethod = makeAccessible(writeMethod); | 
|  | 56 | +		this.type = this.readMethod.getReturnType(); | 
|  | 57 | +	} | 
| 56 | 58 | 
 | 
| 57 |  | -   private static Method makeAccessible(final Method method) { | 
| 58 |  | -      if (method != null && !method.isAccessible()) { | 
| 59 |  | -         logger.debug("Making method accessible: {}", method.toString()); | 
| 60 |  | -         method.setAccessible(true); | 
| 61 |  | -      } | 
| 62 |  | -      return method; | 
| 63 |  | -   } | 
|  | 59 | +	private static Method makeAccessible(final Method method) | 
|  | 60 | +	{ | 
|  | 61 | +		if (method != null && !method.isAccessible()) | 
|  | 62 | +		{ | 
|  | 63 | +			logger.debug("Making method accessible: {}", method.toString()); | 
|  | 64 | +			method.setAccessible(true); | 
|  | 65 | +		} | 
|  | 66 | +		return method; | 
|  | 67 | +	} | 
| 64 | 68 | 
 | 
| 65 |  | -   public final Set<String> getCategoriesFromAnnotation() { | 
| 66 |  | -      final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
| 67 |  | -      if (annotation != null) { | 
| 68 |  | -         return new TreeSet<String>(asList(annotation.categories())); | 
| 69 |  | -      } | 
| 70 |  | -      return Collections.emptySet(); | 
| 71 |  | -   } | 
|  | 69 | +	public final Set<String> getCategoriesFromAnnotation() | 
|  | 70 | +	{ | 
|  | 71 | +		final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
|  | 72 | +		if (annotation != null) | 
|  | 73 | +		{ | 
|  | 74 | +			return new TreeSet<String>(asList(annotation.categories())); | 
|  | 75 | +		} | 
|  | 76 | +		return Collections.emptySet(); | 
|  | 77 | +	} | 
| 72 | 78 | 
 | 
| 73 |  | -   public boolean isExcludedByAnnotation() { | 
| 74 |  | -      final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
| 75 |  | -      return annotation != null && annotation.excluded(); | 
| 76 |  | -   } | 
|  | 79 | +	public boolean isExcludedByAnnotation() | 
|  | 80 | +	{ | 
|  | 81 | +		final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
|  | 82 | +		return annotation != null && annotation.excluded(); | 
|  | 83 | +	} | 
| 77 | 84 | 
 | 
| 78 |  | -   public String getPropertyName() { | 
| 79 |  | -      return this.propertyName; | 
| 80 |  | -   } | 
|  | 85 | +	public String getPropertyName() | 
|  | 86 | +	{ | 
|  | 87 | +		return this.propertyName; | 
|  | 88 | +	} | 
| 81 | 89 | 
 | 
| 82 |  | -   /** | 
| 83 |  | -    * @return The annotations of the getter used to access this property. | 
| 84 |  | -    */ | 
| 85 |  | -   public Set<Annotation> getReadMethodAnnotations() { | 
| 86 |  | -      return new LinkedHashSet<Annotation>(asList(readMethod.getAnnotations())); | 
| 87 |  | -   } | 
|  | 90 | +	/** | 
|  | 91 | +	 * @return The annotations of the getter used to access this property. | 
|  | 92 | +	 */ | 
|  | 93 | +	public Set<Annotation> getReadMethodAnnotations() | 
|  | 94 | +	{ | 
|  | 95 | +		return new LinkedHashSet<Annotation>(asList(readMethod.getAnnotations())); | 
|  | 96 | +	} | 
| 88 | 97 | 
 | 
| 89 |  | -   public <T extends Annotation> T getReadMethodAnnotation(final Class<T> annotationClass) { | 
| 90 |  | -      final Set<? extends Annotation> annotations = getReadMethodAnnotations(); | 
| 91 |  | -      assert (annotations != null) : "Something is wrong here. " | 
| 92 |  | -            + "The contract of getReadAnnotations() guarantees a non-null return value."; | 
| 93 |  | -      for (final Annotation annotation : annotations) { | 
| 94 |  | -         if (annotationClass.isAssignableFrom(annotation.annotationType())) { | 
| 95 |  | -            return annotationClass.cast(annotation); | 
| 96 |  | -         } | 
| 97 |  | -      } | 
| 98 |  | -      return null; | 
| 99 |  | -   } | 
|  | 98 | +	public <T extends Annotation> T getReadMethodAnnotation(final Class<T> annotationClass) | 
|  | 99 | +	{ | 
|  | 100 | +		final Set<? extends Annotation> annotations = getReadMethodAnnotations(); | 
|  | 101 | +		assert (annotations != null) : "Something is wrong here. " + | 
|  | 102 | +				"The contract of getReadAnnotations() guarantees a non-null return value."; | 
|  | 103 | +		for (final Annotation annotation : annotations) | 
|  | 104 | +		{ | 
|  | 105 | +			if (annotationClass.isAssignableFrom(annotation.annotationType())) | 
|  | 106 | +			{ | 
|  | 107 | +				return annotationClass.cast(annotation); | 
|  | 108 | +			} | 
|  | 109 | +		} | 
|  | 110 | +		return null; | 
|  | 111 | +	} | 
| 100 | 112 | 
 | 
| 101 |  | -   public BeanPropertyElementSelector getElementSelector() { | 
| 102 |  | -      return new BeanPropertyElementSelector(this.propertyName); | 
| 103 |  | -   } | 
|  | 113 | +	public BeanPropertyElementSelector getElementSelector() | 
|  | 114 | +	{ | 
|  | 115 | +		return new BeanPropertyElementSelector(this.propertyName); | 
|  | 116 | +	} | 
| 104 | 117 | 
 | 
| 105 |  | -   public Object get(final Object target) { | 
| 106 |  | -      if (target == null) { | 
| 107 |  | -         return null; | 
| 108 |  | -      } | 
| 109 |  | -      try { | 
| 110 |  | -         return readMethod.invoke(target); | 
| 111 |  | -      } catch (final Exception cause) { | 
| 112 |  | -         throw new PropertyReadException(propertyName, target.getClass(), cause); | 
| 113 |  | -      } | 
| 114 |  | -   } | 
|  | 118 | +	public Object get(final Object target) | 
|  | 119 | +	{ | 
|  | 120 | +		if (target == null) | 
|  | 121 | +		{ | 
|  | 122 | +			return null; | 
|  | 123 | +		} | 
|  | 124 | +		try | 
|  | 125 | +		{ | 
|  | 126 | +			return readMethod.invoke(target); | 
|  | 127 | +		} | 
|  | 128 | +		catch (final Exception cause) | 
|  | 129 | +		{ | 
|  | 130 | +			throw new PropertyReadException(propertyName, target.getClass(), cause); | 
|  | 131 | +		} | 
|  | 132 | +	} | 
| 115 | 133 | 
 | 
| 116 |  | -   public void set(final Object target, final Object value) { | 
| 117 |  | -      if (target == null) { | 
| 118 |  | -         logger.info("Couldn't set new value '{}' for property '{}' " + "because the target object is null", value, | 
| 119 |  | -               propertyName); | 
| 120 |  | -      } else if (writeMethod == null) { | 
| 121 |  | -         logger.debug("No setter found for property '{}'", propertyName); | 
| 122 |  | -         tryToReplaceContentOfCollectionTypes(target, value); | 
| 123 |  | -      } else { | 
| 124 |  | -         invokeWriteMethod(target, value); | 
| 125 |  | -      } | 
| 126 |  | -   } | 
|  | 134 | +	public void set(final Object target, final Object value) | 
|  | 135 | +	{ | 
|  | 136 | +		if (target == null) | 
|  | 137 | +		{ | 
|  | 138 | +			logger.info("Couldn't set new value '{}' for property '{}' " + | 
|  | 139 | +					"because the target object is null", value, propertyName); | 
|  | 140 | +		} | 
|  | 141 | +		else if (writeMethod == null) | 
|  | 142 | +		{ | 
|  | 143 | +			logger.debug("No setter found for property '{}'", propertyName); | 
|  | 144 | +			tryToReplaceContentOfCollectionTypes(target, value); | 
|  | 145 | +		} | 
|  | 146 | +		else | 
|  | 147 | +		{ | 
|  | 148 | +			invokeWriteMethod(target, value); | 
|  | 149 | +		} | 
|  | 150 | +	} | 
| 127 | 151 | 
 | 
| 128 |  | -   public void unset(final Object target) { | 
| 129 |  | -      set(target, null); | 
| 130 |  | -   } | 
|  | 152 | +	public void unset(final Object target) | 
|  | 153 | +	{ | 
|  | 154 | +		set(target, null); | 
|  | 155 | +	} | 
| 131 | 156 | 
 | 
| 132 |  | -   @SuppressWarnings("unchecked") | 
| 133 |  | -   private void tryToReplaceContentOfCollectionTypes(final Object target, final Object value) { | 
| 134 |  | -      if (Collection.class.isAssignableFrom(readMethod.getReturnType())) { | 
| 135 |  | -         if (tryToReplaceCollectionContent((Collection<Object>) get(target), (Collection<Object>) value)) { | 
| 136 |  | -            return; | 
| 137 |  | -         } | 
| 138 |  | -      } | 
| 139 |  | -      if (Map.class.isAssignableFrom(readMethod.getReturnType())) { | 
| 140 |  | -         if (tryToReplaceMapContent((Map<Object, Object>) get(target), (Map<Object, Object>) value)) { | 
| 141 |  | -            return; | 
| 142 |  | -         } | 
| 143 |  | -      } | 
| 144 |  | -      logger.info("Couldn't set new value '{}' for property '{}'", value, propertyName); | 
| 145 |  | -   } | 
|  | 157 | +	@SuppressWarnings("unchecked") | 
|  | 158 | +	private void tryToReplaceContentOfCollectionTypes(final Object target, final Object value) | 
|  | 159 | +	{ | 
|  | 160 | +		if (Collection.class.isAssignableFrom(readMethod.getReturnType())) | 
|  | 161 | +		{ | 
|  | 162 | +			if (tryToReplaceCollectionContent((Collection<Object>) get(target), (Collection<Object>) value)) | 
|  | 163 | +			{ | 
|  | 164 | +				return; | 
|  | 165 | +			} | 
|  | 166 | +		} | 
|  | 167 | +		if (Map.class.isAssignableFrom(readMethod.getReturnType())) | 
|  | 168 | +		{ | 
|  | 169 | +			if (tryToReplaceMapContent((Map<Object, Object>) get(target), (Map<Object, Object>) value)) | 
|  | 170 | +			{ | 
|  | 171 | +				return; | 
|  | 172 | +			} | 
|  | 173 | +		} | 
|  | 174 | +		logger.info("Couldn't set new value '{}' for property '{}'", value, propertyName); | 
|  | 175 | +	} | 
| 146 | 176 | 
 | 
| 147 |  | -   private void invokeWriteMethod(final Object target, final Object value) { | 
| 148 |  | -      try { | 
| 149 |  | -         writeMethod.invoke(target, value); | 
| 150 |  | -      } catch (final Exception cause) { | 
| 151 |  | -         throw new PropertyWriteException(propertyName, target.getClass(), value, cause); | 
| 152 |  | -      } | 
| 153 |  | -   } | 
|  | 177 | +	private void invokeWriteMethod(final Object target, final Object value) | 
|  | 178 | +	{ | 
|  | 179 | +		try | 
|  | 180 | +		{ | 
|  | 181 | +			writeMethod.invoke(target, value); | 
|  | 182 | +		} | 
|  | 183 | +		catch (final Exception cause) | 
|  | 184 | +		{ | 
|  | 185 | +			throw new PropertyWriteException(propertyName, target.getClass(), value, cause); | 
|  | 186 | +		} | 
|  | 187 | +	} | 
| 154 | 188 | 
 | 
| 155 |  | -   private static boolean tryToReplaceCollectionContent(final Collection<Object> target, final Collection<Object> value) { | 
| 156 |  | -      if (target == null) { | 
| 157 |  | -         return false; | 
| 158 |  | -      } | 
| 159 |  | -      try { | 
| 160 |  | -         target.clear(); | 
| 161 |  | -         target.addAll(value); | 
| 162 |  | -         return true; | 
| 163 |  | -      } catch (final Exception unmodifiable) { | 
| 164 |  | -         logger.debug("Failed to replace content of existing Collection", unmodifiable); | 
| 165 |  | -         return false; | 
| 166 |  | -      } | 
| 167 |  | -   } | 
|  | 189 | +	private static boolean tryToReplaceCollectionContent(final Collection<Object> target, | 
|  | 190 | +														 final Collection<Object> value) | 
|  | 191 | +	{ | 
|  | 192 | +		if (target == null) | 
|  | 193 | +		{ | 
|  | 194 | +			return false; | 
|  | 195 | +		} | 
|  | 196 | +		try | 
|  | 197 | +		{ | 
|  | 198 | +			target.clear(); | 
|  | 199 | +			target.addAll(value); | 
|  | 200 | +			return true; | 
|  | 201 | +		} | 
|  | 202 | +		catch (final Exception unmodifiable) | 
|  | 203 | +		{ | 
|  | 204 | +			logger.debug("Failed to replace content of existing Collection", unmodifiable); | 
|  | 205 | +			return false; | 
|  | 206 | +		} | 
|  | 207 | +	} | 
| 168 | 208 | 
 | 
| 169 |  | -   private static boolean tryToReplaceMapContent(final Map<Object, Object> target, final Map<Object, Object> value) { | 
| 170 |  | -      if (target == null) { | 
| 171 |  | -         return false; | 
| 172 |  | -      } | 
| 173 |  | -      try { | 
| 174 |  | -         target.clear(); | 
| 175 |  | -         target.putAll(value); | 
| 176 |  | -         return true; | 
| 177 |  | -      } catch (final Exception unmodifiable) { | 
| 178 |  | -         logger.debug("Failed to replace content of existing Map", unmodifiable); | 
| 179 |  | -         return false; | 
| 180 |  | -      } | 
| 181 |  | -   } | 
|  | 209 | +	private static boolean tryToReplaceMapContent(final Map<Object, Object> target, | 
|  | 210 | +												  final Map<Object, Object> value) | 
|  | 211 | +	{ | 
|  | 212 | +		if (target == null) | 
|  | 213 | +		{ | 
|  | 214 | +			return false; | 
|  | 215 | +		} | 
|  | 216 | +		try | 
|  | 217 | +		{ | 
|  | 218 | +			target.clear(); | 
|  | 219 | +			target.putAll(value); | 
|  | 220 | +			return true; | 
|  | 221 | +		} | 
|  | 222 | +		catch (final Exception unmodifiable) | 
|  | 223 | +		{ | 
|  | 224 | +			logger.debug("Failed to replace content of existing Map", unmodifiable); | 
|  | 225 | +			return false; | 
|  | 226 | +		} | 
|  | 227 | +	} | 
| 182 | 228 | 
 | 
| 183 |  | -   public Class<?> getType() { | 
| 184 |  | -      return this.type; | 
| 185 |  | -   } | 
|  | 229 | +	public Class<?> getType() | 
|  | 230 | +	{ | 
|  | 231 | +		return this.type; | 
|  | 232 | +	} | 
| 186 | 233 | 
 | 
| 187 |  | -   @Override | 
| 188 |  | -   public String toString() { | 
| 189 |  | -      final StringBuilder sb = new StringBuilder("PropertyAccessor{"); | 
| 190 |  | -      sb.append("propertyName='").append(propertyName).append('\''); | 
| 191 |  | -      sb.append(", type=").append(type.getCanonicalName()); | 
| 192 |  | -      sb.append(", source=").append(readMethod.getDeclaringClass().getCanonicalName()); | 
| 193 |  | -      sb.append(", hasWriteMethod=").append(writeMethod != null); | 
| 194 |  | -      sb.append('}'); | 
| 195 |  | -      return sb.toString(); | 
| 196 |  | -   } | 
|  | 234 | +	@Override | 
|  | 235 | +	public String toString() | 
|  | 236 | +	{ | 
|  | 237 | +		final StringBuilder sb = new StringBuilder("PropertyAccessor{"); | 
|  | 238 | +		sb.append("propertyName='").append(propertyName).append('\''); | 
|  | 239 | +		sb.append(", type=").append(type.getCanonicalName()); | 
|  | 240 | +		sb.append(", source=").append(readMethod.getDeclaringClass().getCanonicalName()); | 
|  | 241 | +		sb.append(", hasWriteMethod=").append(writeMethod != null); | 
|  | 242 | +		sb.append('}'); | 
|  | 243 | +		return sb.toString(); | 
|  | 244 | +	} | 
| 197 | 245 | 
 | 
| 198 | 246 |    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { | 
| 199 | 247 |       T ann = getReadMethodAnnotation(annotationClass); | 
|  | 
0 commit comments