|  | 
| 35 | 35 | import de.danielbechler.diff.selector.BeanPropertyElementSelector; | 
| 36 | 36 | import de.danielbechler.util.Assert; | 
| 37 | 37 | 
 | 
| 38 |  | -public class PropertyAccessor implements PropertyAwareAccessor | 
| 39 |  | -{ | 
| 40 |  | -	private static final Logger logger = LoggerFactory.getLogger(PropertyAccessor.class); | 
|  | 38 | +public class PropertyAccessor implements PropertyAwareAccessor { | 
|  | 39 | +   private static final Logger logger = LoggerFactory.getLogger(PropertyAccessor.class); | 
| 41 | 40 | 
 | 
| 42 |  | -	private final String propertyName; | 
| 43 |  | -	private final Class<?> type; | 
| 44 |  | -	private final Method readMethod; | 
| 45 |  | -	private final Method writeMethod; | 
|  | 41 | +   private final String propertyName; | 
|  | 42 | +   private final Class<?> type; | 
|  | 43 | +   private final Method readMethod; | 
|  | 44 | +   private final Method writeMethod; | 
| 46 | 45 |    private final Field field; | 
| 47 | 46 | 
 | 
| 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; | 
|  | 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; | 
| 53 | 51 |       this.field = f; | 
| 54 |  | -		this.readMethod = makeAccessible(readMethod); | 
| 55 |  | -		this.writeMethod = makeAccessible(writeMethod); | 
| 56 |  | -		this.type = this.readMethod.getReturnType(); | 
| 57 |  | -	} | 
|  | 52 | +      this.readMethod = makeAccessible(readMethod); | 
|  | 53 | +      this.writeMethod = makeAccessible(writeMethod); | 
|  | 54 | +      this.type = this.readMethod.getReturnType(); | 
|  | 55 | +   } | 
| 58 | 56 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 68 | 64 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 78 | 72 | 
 | 
| 79 |  | -	public boolean isExcludedByAnnotation() | 
| 80 |  | -	{ | 
| 81 |  | -		final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
| 82 |  | -		return annotation != null && annotation.excluded(); | 
| 83 |  | -	} | 
|  | 73 | +   public boolean isExcludedByAnnotation() { | 
|  | 74 | +      final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class); | 
|  | 75 | +      return annotation != null && annotation.excluded(); | 
|  | 76 | +   } | 
| 84 | 77 | 
 | 
| 85 |  | -	public String getPropertyName() | 
| 86 |  | -	{ | 
| 87 |  | -		return this.propertyName; | 
| 88 |  | -	} | 
|  | 78 | +   public String getPropertyName() { | 
|  | 79 | +      return this.propertyName; | 
|  | 80 | +   } | 
| 89 | 81 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 97 | 88 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 112 | 100 | 
 | 
| 113 |  | -	public BeanPropertyElementSelector getElementSelector() | 
| 114 |  | -	{ | 
| 115 |  | -		return new BeanPropertyElementSelector(this.propertyName); | 
| 116 |  | -	} | 
|  | 101 | +   public BeanPropertyElementSelector getElementSelector() { | 
|  | 102 | +      return new BeanPropertyElementSelector(this.propertyName); | 
|  | 103 | +   } | 
| 117 | 104 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 133 | 115 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 151 | 127 | 
 | 
| 152 |  | -	public void unset(final Object target) | 
| 153 |  | -	{ | 
| 154 |  | -		set(target, null); | 
| 155 |  | -	} | 
|  | 128 | +   public void unset(final Object target) { | 
|  | 129 | +      set(target, null); | 
|  | 130 | +   } | 
| 156 | 131 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 176 | 146 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 188 | 154 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 208 | 168 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 228 | 182 | 
 | 
| 229 |  | -	public Class<?> getType() | 
| 230 |  | -	{ | 
| 231 |  | -		return this.type; | 
| 232 |  | -	} | 
|  | 183 | +   public Class<?> getType() { | 
|  | 184 | +      return this.type; | 
|  | 185 | +   } | 
| 233 | 186 | 
 | 
| 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 |  | -	} | 
|  | 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 | +   } | 
| 245 | 197 | 
 | 
| 246 | 198 |    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { | 
| 247 | 199 |       T ann = getReadMethodAnnotation(annotationClass); | 
| 248 | 200 |       if (ann != null) { | 
| 249 | 201 |          return ann; | 
| 250 | 202 |       } | 
| 251 |  | -      return field.getAnnotation(annotationClass); | 
|  | 203 | +      return field == null ? null : field.getAnnotation(annotationClass); | 
| 252 | 204 |    } | 
| 253 | 205 | 
 | 
| 254 | 206 |    public int getFieldModifiers() { | 
| 255 |  | -      return field.getModifiers(); | 
|  | 207 | +      return field == null ? 0 : field.getModifiers(); | 
| 256 | 208 |    } | 
| 257 | 209 | 
 | 
| 258 | 210 | } | 
0 commit comments