• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2008, SnakeYAML
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package org.yaml.snakeyaml.introspector;
15 
16 import java.beans.PropertyDescriptor;
17 import java.lang.annotation.Annotation;
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Type;
20 import java.util.List;
21 import org.yaml.snakeyaml.error.YAMLException;
22 import org.yaml.snakeyaml.util.ArrayUtils;
23 
24 /**
25  * <p>
26  * A <code>MethodProperty</code> is a <code>Property</code> which is accessed through accessor
27  * methods (setX, getX). It is possible to have a <code>MethodProperty</code> which has only setter,
28  * only getter, or both. It is not possible to have a <code>MethodProperty</code> which has neither
29  * setter nor getter.
30  * </p>
31  */
32 public class MethodProperty extends GenericProperty {
33 
34   private final PropertyDescriptor property;
35   private final boolean readable;
36   private final boolean writable;
37 
discoverGenericType(PropertyDescriptor property)38   private static Type discoverGenericType(PropertyDescriptor property) {
39     Method readMethod = property.getReadMethod();
40     if (readMethod != null) {
41       return readMethod.getGenericReturnType();
42     }
43 
44     Method writeMethod = property.getWriteMethod();
45     if (writeMethod != null) {
46       Type[] paramTypes = writeMethod.getGenericParameterTypes();
47       if (paramTypes.length > 0) {
48         return paramTypes[0];
49       }
50     }
51     /*
52      * This actually may happen if PropertyDescriptor is of type IndexedPropertyDescriptor and it
53      * has only IndexedGetter/Setter. ATM we simply skip type discovery.
54      */
55     return null;
56   }
57 
MethodProperty(PropertyDescriptor property)58   public MethodProperty(PropertyDescriptor property) {
59     super(property.getName(), property.getPropertyType(),
60         MethodProperty.discoverGenericType(property));
61     this.property = property;
62     this.readable = property.getReadMethod() != null;
63     this.writable = property.getWriteMethod() != null;
64   }
65 
66   @Override
set(Object object, Object value)67   public void set(Object object, Object value) throws Exception {
68     if (!writable) {
69       throw new YAMLException(
70           "No writable property '" + getName() + "' on class: " + object.getClass().getName());
71     }
72     property.getWriteMethod().invoke(object, value);
73   }
74 
75   @Override
get(Object object)76   public Object get(Object object) {
77     try {
78       property.getReadMethod().setAccessible(true);// issue 50
79       return property.getReadMethod().invoke(object);
80     } catch (Exception e) {
81       throw new YAMLException("Unable to find getter for property '" + property.getName()
82           + "' on object " + object + ":" + e);
83     }
84   }
85 
86   /**
87    * Returns the annotations that are present on read and write methods of this property or empty
88    * {@code List} if there're no annotations.
89    *
90    * @return the annotations that are present on this property or empty {@code List} if there're no
91    *         annotations
92    */
93   @Override
getAnnotations()94   public List<Annotation> getAnnotations() {
95     List<Annotation> annotations;
96     if (isReadable() && isWritable()) {
97       annotations = ArrayUtils.toUnmodifiableCompositeList(
98           property.getReadMethod().getAnnotations(), property.getWriteMethod().getAnnotations());
99     } else if (isReadable()) {
100       annotations = ArrayUtils.toUnmodifiableList(property.getReadMethod().getAnnotations());
101     } else {
102       annotations = ArrayUtils.toUnmodifiableList(property.getWriteMethod().getAnnotations());
103     }
104     return annotations;
105   }
106 
107   /**
108    * Returns property's annotation for the given type or {@code null} if it's not present. If the
109    * annotation is present on both read and write methods, the annotation on read method takes
110    * precedence.
111    *
112    * @param annotationType the type of the annotation to be returned
113    * @return property's annotation for the given type or {@code null} if it's not present
114    */
115   @Override
getAnnotation(Class<A> annotationType)116   public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
117     A annotation = null;
118     if (isReadable()) {
119       annotation = property.getReadMethod().getAnnotation(annotationType);
120     }
121     if (annotation == null && isWritable()) {
122       annotation = property.getWriteMethod().getAnnotation(annotationType);
123     }
124     return annotation;
125   }
126 
127   @Override
isWritable()128   public boolean isWritable() {
129     return writable;
130   }
131 
132   @Override
isReadable()133   public boolean isReadable() {
134     return readable;
135   }
136 
137 }
138