http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2c3a7cb5/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMap.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMap.java b/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMap.java deleted file mode 100644 index adef3ab..0000000 --- a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMap.java +++ /dev/null @@ -1,489 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - ***************************************************************************************************************************/ -package org.apache.juneau; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.parser.*; -import org.apache.juneau.transform.*; -import org.apache.juneau.xml.annotation.*; - -/** - * Java bean wrapper class. - * - * - * <h6 class='topic'>Description</h6> - * <p> - * A wrapper that wraps Java bean instances inside of a {@link Map} interface that allows - * properties on the wrapped object can be accessed using the {@link Map#get(Object) get()} and {@link Map#put(Object,Object) put()} methods. - * <p> - * Use the {@link BeanContext} class to create instances of this class. - * - * - * <h6 class='topic'>Bean property order</h6> - * <p> - * The order of the properties returned by the {@link Map#keySet() keySet()} and {@link Map#entrySet() entrySet()} methods are as follows: - * <ul class='spaced-list'> - * <li>If {@link Bean @Bean} annotation is specified on class, then the order is the same as the list of properties in the annotation. - * <li>If {@link Bean @Bean} annotation is not specified on the class, then the order is the same as that returned - * by the {@link java.beans.BeanInfo} class (i.e. ordered by definition in the class). - * </ul> - * <br> - * The order can also be overridden through the use of a {@link BeanTransform}. - * - * - * <h6 class='topic'>POJO transforms</h6> - * <p> - * If {@link PojoTransform PojoTransforms} are defined on the class types of the properties of this bean or the bean properties themselves, the - * {@link #get(Object)} and {@link #put(String, Object)} methods will automatically - * transform the property value to and from the serialized form. - * - * @author Barry M. Caceres - * @author James Bognar ([email protected]) - * @param <T> Specifies the type of object that this map encapsulates. - */ -public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T> { - - /** The wrapped object. */ - protected T bean; - - /** Temporary holding cache for beans with read-only properties. Normally null. */ - protected Map<String,Object> propertyCache; - - /** Temporary holding cache for bean properties of array types when the add() method is being used. */ - protected Map<String,List<?>> arrayPropertyCache; - - /** The BeanMeta associated with the class of the object. */ - protected BeanMeta<T> meta; - - /** - * Instance of this class are instantiated through the BeanContext class. - * - * @param bean The bean to wrap inside this map. - * @param meta The metadata associated with the bean class. - */ - protected BeanMap(T bean, BeanMeta<T> meta) { - this.bean = bean; - this.meta = meta; - if (meta.constructorArgs.length > 0) - propertyCache = new TreeMap<String,Object>(); - } - - /** - * Returns the metadata associated with this bean map. - * - * @return The metadata associated with this bean map. - */ - public BeanMeta<T> getMeta() { - return meta; - } - - /** - * Returns the wrapped bean object. - * Triggers bean creation if bean has read-only properties set through a constructor - * defined by the {@link BeanConstructor} annotation. - * - * @return The inner bean object. - */ - public T getBean() { - T b = getBean(true); - - // If we have any arrays that need to be constructed, do it now. - if (arrayPropertyCache != null) { - for (Map.Entry<String,List<?>> e : arrayPropertyCache.entrySet()) { - String key = e.getKey(); - List<?> value = e.getValue(); - BeanPropertyMeta<T> bpm = getPropertyMeta(key); - try { - bpm.setArray(b, value); - } catch (Exception e1) { - throw new RuntimeException(e1); - } - } - arrayPropertyCache = null; - } - return b; - } - - /** - * Returns the wrapped bean object. - * <p> - * If <code>create</code> is <jk>false</jk>, then this method may return <jk>null</jk> - * if the bean has read-only properties set through a constructor - * defined by the {@link BeanConstructor} annotation. - * <p> - * This method does NOT always return the bean in it's final state. - * Array properties temporary stored as ArrayLists are not finalized - * until the {@link #getBean()} method is called. - * - * @param create If bean hasn't been instantiated yet, then instantiate it. - * @return The inner bean object. - */ - public T getBean(boolean create) { - /** If this is a read-only bean, then we need to create it. */ - if (bean == null && create && meta.constructorArgs.length > 0) { - String[] props = meta.constructorArgs; - Constructor<T> c = meta.constructor; - Object[] args = new Object[props.length]; - for (int i = 0; i < props.length; i++) - args[i] = propertyCache.remove(props[i]); - try { - bean = c.newInstance(args); - for (Map.Entry<String,Object> e : propertyCache.entrySet()) - put(e.getKey(), e.getValue()); - propertyCache = null; - } catch (Exception e) { - throw new BeanRuntimeException(e); - } - } - return bean; - } - - /** - * Returns the value of the property identified as the URI property (annotated with {@link BeanProperty#beanUri()} as <jk>true</jk>). - * - * @return The URI value, or <jk>null</jk> if no URI property exists on this bean. - */ - public Object getBeanUri() { - BeanMeta<T> bm = getMeta(); - return bm.hasBeanUriProperty() ? bm.getBeanUriProperty().get(this) : null; - } - - /** - * Sets the bean URI property if the bean has a URI property. - * Ignored otherwise. - * - * @param o The bean URI object. - * @return If the bean context setting {@code beanMapPutReturnsOldValue} is <jk>true</jk>, then the old value of the property is returned. - * Otherwise, this method always returns <jk>null</jk>. - */ - public Object putBeanUri(Object o) { - BeanMeta<T> bm = getMeta(); - return bm.hasBeanUriProperty() ? bm.getBeanUriProperty().set(this, o) : null; - } - - /** - * Sets a property on the bean. - * <p> - * If there is a {@link PojoTransform} associated with this bean property or bean property type class, then - * you must pass in a transformed value. - * For example, if the bean property type class is a {@link Date} and the bean property has the - * {@link org.apache.juneau.transforms.DateTransform.ISO8601DT} transform associated with it through the - * {@link BeanProperty#transform() @BeanProperty.transform()} annotation, the value being passed in must be - * a String containing an ISO8601 date-time string value. - * - * <dl> - * <dt>Example:</dt> - * <dd> - * <p class='bcode'> - * <jc>// Construct a bean with a 'birthDate' Date field</jc> - * Person p = <jk>new</jk> Person(); - * - * <jc>// Create a bean context and add the ISO8601 date-time transform</jc> - * BeanContext beanContext = <jk>new</jk> BeanContext().addTransform(DateTransform.ISO8601DT.<jk>class</jk>); - * - * <jc>// Wrap our bean in a bean map</jc> - * BeanMap<Person> b = beanContext.forBean(p); - * - * <jc>// Set the field</jc> - * myBeanMap.put(<js>"birthDate"</js>, <js>"'1901-03-03T04:05:06-5000'"</js>); - * </p> - * </dd> - * </dl> - * - * @param property The name of the property to set. - * @param value The value to set the property to. - * @return If the bean context setting {@code beanMapPutReturnsOldValue} is <jk>true</jk>, then the old value of the property is returned. - * Otherwise, this method always returns <jk>null</jk>. - * @throws RuntimeException if any of the following occur. - * <ul class='spaced-list'> - * <li>BeanMapEntry does not exist on the underlying object. - * <li>Security settings prevent access to the underlying object setter method. - * <li>An exception occurred inside the setter method. - * </ul> - */ - @Override /* Map */ - public Object put(String property, Object value) { - BeanPropertyMeta<T> p = meta.properties.get(property); - if (p == null) { - if (meta.ctx.ignoreUnknownBeanProperties) - return null; - if (property.equals("<uri>") && meta.uriProperty != null) - return meta.uriProperty.set(this, value); - - // If this bean has subtypes, and we haven't set the subtype yet, - // store the property in a temporary cache until the bean can be instantiated. - // This eliminates the need for requiring that the sub type attribute be provided first. - if (meta.subTypeIdProperty != null) { - if (propertyCache == null) - propertyCache = new TreeMap<String,Object>(); - return propertyCache.put(property, value); - } - - throw new BeanRuntimeException(meta.c, "Bean property ''{0}'' not found.", property); - } - if (meta.transform != null) - if (meta.transform.writeProperty(this.bean, property, value)) - return null; - return p.set(this, value); - } - - /** - * Add a value to a collection or array property. - * <p> - * As a general rule, adding to arrays is not recommended since the array must be recreate each time - * this method is called. - * - * @param property Property name or child-element name (if {@link Xml#childName()} is specified). - * @param value The value to add to the collection or array. - */ - public void add(String property, Object value) { - BeanPropertyMeta<T> p = meta.properties.get(property); - if (p == null) { - if (meta.ctx.ignoreUnknownBeanProperties) - return; - throw new BeanRuntimeException(meta.c, "Bean property ''{0}'' not found.", property); - } - p.add(this, value); - } - - - /** - * Gets a property on the bean. - * <p> - * If there is a {@link PojoTransform} associated with this bean property or bean property type class, then - * this method will return the transformed value. - * For example, if the bean property type class is a {@link Date} and the bean property has the - * {@link org.apache.juneau.transforms.DateTransform.ISO8601DT} transform associated with it through the - * {@link BeanProperty#transform() @BeanProperty.transform()} annotation, this method will return a String - * containing an ISO8601 date-time string value. - * - * <dl> - * <dt>Example:</dt> - * <dd> - * <p class='bcode'> - * <jc>// Construct a bean with a 'birthDate' Date field</jc> - * Person p = <jk>new</jk> Person(); - * p.setBirthDate(<jk>new</jk> Date(1, 2, 3, 4, 5, 6)); - * - * <jc>// Create a bean context and add the ISO8601 date-time transform</jc> - * BeanContext beanContext = <jk>new</jk> BeanContext().addTransform(DateTransform.ISO8601DT.<jk>class</jk>); - * - * <jc>// Wrap our bean in a bean map</jc> - * BeanMap<Person> b = beanContext.forBean(p); - * - * <jc>// Get the field as a string (i.e. "'1901-03-03T04:05:06-5000'")</jc> - * String s = myBeanMap.get(<js>"birthDate"</js>); - * </p> - * </dd> - * </dl> - * - * @param property The name of the property to get. - * @throws RuntimeException if any of the following occur. - * <ol> - * <li>BeanMapEntry does not exist on the underlying object. - * <li>Security settings prevent access to the underlying object getter method. - * <li>An exception occurred inside the getter method. - * </ol> - */ - @Override /* Map */ - public Object get(Object property) { - BeanPropertyMeta<T> p = meta.properties.get(property); - if (p == null) - return null; - if (meta.transform != null && property != null) - return meta.transform.readProperty(this.bean, property.toString(), p.get(this)); - return p.get(this); - } - - /** - * Convenience method for setting multiple property values by passing in JSON (or other) text. - * <p> - * Typically the input is going to be JSON, although the actual data type - * depends on the default parser specified by the {@link BeanContext#BEAN_defaultParser} property - * value on the config that created the context that created this map. - * - * <dl> - * <dt>Example:</dt> - * <dd> - * <p class='bcode'> - * aPersonBean.load(<js>"{name:'John Smith',age:21}"</js>) - * </p> - * </dd> - * </dl> - * - * @param input The text that will get parsed into a map and then added to this map. - * @return This object (for method chaining). - * @throws ParseException If the input contains a syntax error or is malformed. - */ - public BeanMap<T> load(String input) throws ParseException { - putAll(new ObjectMap(input, this.meta.ctx.defaultParser)); - return this; - } - - /** - * Convenience method for setting multiple property values by passing in a reader. - * - * @param r The text that will get parsed into a map and then added to this map. - * @param p The parser to use to parse the text. - * @return This object (for method chaining). - * @throws ParseException If the input contains a syntax error or is malformed. - * @throws IOException Thrown by <code>Reader</code>. - */ - public BeanMap<T> load(Reader r, ReaderParser p) throws ParseException, IOException { - putAll(new ObjectMap(r, p)); - return this; - } - - /** - * Convenience method for loading this map with the contents of the specified map. - * <p> - * Identical to {@link #putAll(Map)} except as a fluent-style method. - * - * @param entries The map containing the entries to add to this map. - * @return This object (for method chaining). - */ - @SuppressWarnings({"unchecked","rawtypes"}) - public BeanMap<T> load(Map entries) { - putAll(entries); - return this; - } - - /** - * Returns the names of all properties associated with the bean. - * <p> - * The returned set is unmodifiable. - */ - @Override /* Map */ - public Set<String> keySet() { - return meta.properties.keySet(); - } - - /** - * Returns the specified property on this bean map. - * <p> - * Allows you to get and set an individual property on a bean without having a - * handle to the bean itself by using the {@link BeanMapEntry#getValue()} - * and {@link BeanMapEntry#setValue(Object)} methods. - * <p> - * This method can also be used to get metadata on a property by - * calling the {@link BeanMapEntry#getMeta()} method. - * - * @param propertyName The name of the property to look up. - * @return The bean property, or null if the bean has no such property. - */ - public BeanMapEntry<T> getProperty(String propertyName) { - BeanPropertyMeta<T> p = meta.properties.get(propertyName); - if (p == null) - return null; - return new BeanMapEntry<T>(this, p); - } - - /** - * Returns the metadata on the specified property. - * - * @param propertyName The name of the bean property. - * @return Metadata on the specified property, or <jk>null</jk> if that property does not exist. - */ - public BeanPropertyMeta<T> getPropertyMeta(String propertyName) { - return meta.properties.get(propertyName); - } - - /** - * Returns the {@link ClassMeta} of the wrapped bean. - * - * @return The class type of the wrapped bean. - */ - @Override /* Delagate */ - public ClassMeta<T> getClassMeta() { - return this.meta.getClassMeta(); - } - - /** - * Returns all the properties associated with the bean. - */ - @Override /* Map */ - public Set<Entry<String,Object>> entrySet() { - return entrySet(false); - } - - /** - * Returns all the properties associated with the bean. - * @param ignoreNulls - Iterator should not return properties with null values. - * @return A new set. - */ - public Set<Entry<String,Object>> entrySet(final boolean ignoreNulls) { - int todo = 1; // Create a more efficient method. - - // Construct our own anonymous set to implement this function. - Set<Entry<String,Object>> s = new AbstractSet<Entry<String,Object>>() { - - // Get the list of properties from the meta object. - // Note that the HashMap.values() method caches results, so this collection - // will really only be constructed once per bean type since the underlying - // map never changes. - final Collection<BeanPropertyMeta<T>> pSet = meta.properties.values(); - - @Override /* Set */ - public Iterator<java.util.Map.Entry<String, Object>> iterator() { - - // Construct our own anonymous iterator that uses iterators against the meta.properties - // map to maintain position. This prevents us from having to construct any of our own - // collection objects. - return new Iterator<Entry<String,Object>>() { - - final Iterator<BeanPropertyMeta<T>> pIterator = pSet.iterator(); - BeanMapEntry<T> nextEntry; - - @Override /* Iterator */ - public boolean hasNext() { - return nextEntry() != null; - } - - @Override /* Iterator */ - public Map.Entry<String, Object> next() { - BeanMapEntry<T> e = nextEntry(); - nextEntry = null; - return e; - } - - private BeanMapEntry<T> nextEntry() { - if (nextEntry == null) { - while (pIterator.hasNext() && nextEntry == null) { - BeanPropertyMeta<T> bpm = pIterator.next(); - if ((! ignoreNulls) || bpm.get(BeanMap.this) != null) - nextEntry = new BeanMapEntry<T>(BeanMap.this, bpm); - } - } - return nextEntry; - } - - @Override /* Iterator */ - public void remove() { - throw new UnsupportedOperationException("Cannot remove item from iterator."); - } - }; - } - - @Override /* Set */ - public int size() { - return pSet.size(); - } - }; - - return s; - } -} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2c3a7cb5/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMapEntry.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMapEntry.java b/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMapEntry.java deleted file mode 100644 index 34aad38..0000000 --- a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMapEntry.java +++ /dev/null @@ -1,125 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - ***************************************************************************************************************************/ -package org.apache.juneau; - -import java.util.*; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.transform.*; - -/** - * Represents a single entry in a bean map. - * <p> - * This class can be used to get and set property values on a bean, or to get metadata on a property. - * - * <h6 class='topic'>Examples</h6> - * <p class='bcode'> - * <jc>// Construct a new bean</jc> - * Person p = <jk>new</jk> Person(); - * - * <jc>// Wrap it in a bean map</jc> - * BeanMap<Person> b = BeanContext.<jsf>DEFAULT</jsf>.forBean(p); - * - * <jc>// Get a reference to the birthDate property</jc> - * BeanMapEntry birthDate = b.getProperty(<js>"birthDate"</js>); - * - * <jc>// Set the property value</jc> - * birthDate.setValue(<jk>new</jk> Date(1, 2, 3, 4, 5, 6)); - * - * <jc>// Or if the DateTransform.DEFAULT_ISO8601DT is registered with the bean context, set a transformed value</jc> - * birthDate.setValue(<js>"'1901-03-03T04:05:06-5000'"</js>); - * </p> - * - * @author James Bognar ([email protected]) - * - * @param <T> The bean type. - */ -public class BeanMapEntry<T> implements Map.Entry<String,Object> { - private final BeanMap<T> beanMap; - private final BeanPropertyMeta<T> meta; - - /** - * Constructor. - * - * @param beanMap The bean map that this entry belongs to. - * @param property The bean property. - */ - protected BeanMapEntry(BeanMap<T> beanMap, BeanPropertyMeta<T> property) { - this.beanMap = beanMap; - this.meta = property; - } - - @Override /* Map.Entry */ - public String getKey() { - return meta.getName(); - } - - /** - * Returns the value of this property. - * <p> - * If there is a {@link PojoTransform} associated with this bean property or bean property type class, then - * this method will return the transformed value. - * For example, if the bean property type class is a {@link Date} and the bean property has the - * {@link org.apache.juneau.transforms.DateTransform.ISO8601DT} transform associated with it through the - * {@link BeanProperty#transform() @BeanProperty.transform()} annotation, this method will return a String - * containing an ISO8601 date-time string value. - */ - @Override /* Map.Entry */ - public Object getValue() { - return meta.get(this.beanMap); - } - - /** - * Sets the value of this property. - * <p> - * If the property is an array of type {@code X}, then the value can be a {@code Collection<X>} or {@code X[]} or {@code Object[]}. - * <p> - * If the property is a bean type {@code X}, then the value can either be an {@code X} or a {@code Map}. - * <p> - * If there is a {@link PojoTransform} associated with this bean property or bean property type class, then - * you must pass in a transformed value. - * For example, if the bean property type class is a {@link Date} and the bean property has the - * {@link org.apache.juneau.transforms.DateTransform.ISO8601DT} transform associated with it through the - * {@link BeanProperty#transform() @BeanProperty.transform()} annotation, the value being passed in must be - * a String containing an ISO8601 date-time string value. - * - * @return The set value after it's been converted. - */ - @Override /* Map.Entry */ - public Object setValue(Object value) { - return meta.set(this.beanMap, value); - } - - /** - * Returns the bean map that contains this property. - * - * @return The bean map that contains this property. - */ - public BeanMap<T> getBeanMap() { - return this.beanMap; - } - - /** - * Returns the metadata about this bean property. - * - * @return Metadata about this bean property. - */ - public BeanPropertyMeta<T> getMeta() { - return this.meta; - } - - @Override /* Object */ - public String toString() { - return this.getKey() + "=" + this.getValue(); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2c3a7cb5/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMeta.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMeta.java b/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMeta.java deleted file mode 100644 index b5f4092..0000000 --- a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMeta.java +++ /dev/null @@ -1,755 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - ***************************************************************************************************************************/ -package org.apache.juneau; - -import static org.apache.juneau.Visibility.*; -import static org.apache.juneau.internal.ClassUtils.*; - -import java.beans.*; -import java.io.*; -import java.lang.reflect.*; -import java.util.*; -import java.util.Map.*; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.html.*; -import org.apache.juneau.internal.*; -import org.apache.juneau.jena.*; -import org.apache.juneau.transform.*; -import org.apache.juneau.xml.*; - - -/** - * Encapsulates all access to the properties of a bean class (like a souped-up {@link java.beans.BeanInfo}). - * - * - * <h6 class='topic'>Description</h6> - * <p> - * Uses introspection to find all the properties associated with this class. If the {@link Bean @Bean} annotation - * is present on the class, or the class has a {@link BeanTransform} registered with it in the bean context, - * then that information is used to determine the properties on the class. - * Otherwise, the {@code BeanInfo} functionality in Java is used to determine the properties on the class. - * - * - * <h6 class='topic'>Bean property ordering</h6> - * <p> - * The order of the properties are as follows: - * <ul class='spaced-list'> - * <li>If {@link Bean @Bean} annotation is specified on class, then the order is the same as the list of properties in the annotation. - * <li>If {@link Bean @Bean} annotation is not specified on the class, then the order is based on the following. - * <ul> - * <li>Public fields (same order as {@code Class.getFields()}). - * <li>Properties returned by {@code BeanInfo.getPropertyDescriptors()}. - * <li>Non-standard getters/setters with {@link BeanProperty @BeanProperty} annotation defined on them. - * </ul> - * </ul> - * <br> - * The order can also be overridden through the use of an {@link BeanTransform}. - * - * - * @param <T> The class type that this metadata applies to. - * @author Barry M. Caceres - * @author James Bognar ([email protected]) - */ -public class BeanMeta<T> { - - /** The target class type that this meta object describes. */ - protected ClassMeta<T> classMeta; - - /** The target class that this meta object describes. */ - protected Class<T> c; - - /** The properties on the target class. */ - protected Map<String,BeanPropertyMeta<T>> properties; - - /** The getter properties on the target class. */ - protected Map<Method,String> getterProps = new HashMap<Method,String>(); - - /** The setter properties on the target class. */ - protected Map<Method,String> setterProps = new HashMap<Method,String>(); - - /** The bean context that created this metadata object. */ - protected BeanContext ctx; - - /** Optional bean transform associated with the target class. */ - protected BeanTransform<? extends T> transform; - - /** Type variables implemented by this bean. */ - protected Map<Class<?>,Class<?>[]> typeVarImpls; - - /** The constructor for this bean. */ - protected Constructor<T> constructor; - - /** For beans with constructors with BeanConstructor annotation, this is the list of constructor arg properties. */ - protected String[] constructorArgs = new String[0]; - - /** XML-related metadata */ - protected XmlBeanMeta<T> xmlMeta; - - // Other fields - BeanPropertyMeta<T> uriProperty; // The property identified as the URI for this bean (annotated with @BeanProperty.beanUri). - BeanPropertyMeta<T> subTypeIdProperty; // The property indentified as the sub type differentiator property (identified by @Bean.subTypeProperty annotation). - PropertyNamer propertyNamer; // Class used for calculating bean property names. - - BeanMeta() {} - - /** - * Constructor. - * - * @param classMeta The target class. - * @param ctx The bean context that created this object. - * @param transform Optional bean transform associated with the target class. Can be <jk>null</jk>. - */ - protected BeanMeta(ClassMeta<T> classMeta, BeanContext ctx, org.apache.juneau.transform.BeanTransform<? extends T> transform) { - this.classMeta = classMeta; - this.ctx = ctx; - this.transform = transform; - this.c = classMeta.getInnerClass(); - } - - /** - * Returns the {@link ClassMeta} of this bean. - * - * @return The {@link ClassMeta} of this bean. - */ - @BeanIgnore - public ClassMeta<T> getClassMeta() { - return classMeta; - } - - /** - * Initializes this bean meta, and returns an error message if the specified class is not - * a bean for any reason. - * - * @return Reason why this class isn't a bean, or <jk>null</jk> if no problems detected. - * @throws BeanRuntimeException If unexpected error occurs such as invalid annotations on the bean class. - */ - @SuppressWarnings("unchecked") - protected String init() throws BeanRuntimeException { - - try { - Visibility - conVis = ctx.beanConstructorVisibility, - cVis = ctx.beanClassVisibility, - mVis = ctx.beanMethodVisibility, - fVis = ctx.beanFieldVisibility; - - // If @Bean.interfaceClass is specified on the parent class, then we want - // to use the properties defined on that class, not the subclass. - Class<?> c2 = (transform != null && transform.getInterfaceClass() != null ? transform.getInterfaceClass() : c); - - Class<?> stopClass = (transform != null ? transform.getStopClass() : Object.class); - if (stopClass == null) - stopClass = Object.class; - - Map<String,BeanPropertyMeta<T>> normalProps = new LinkedHashMap<String,BeanPropertyMeta<T>>(); - - /// See if this class matches one the patterns in the exclude-class list. - if (ctx.isNotABean(c)) - return "Class matches exclude-class list"; - - if (! cVis.isVisible(c.getModifiers())) - return "Class is not public"; - - if (c.isAnnotationPresent(BeanIgnore.class)) - return "Class is annotated with @BeanIgnore"; - - // Make sure it's serializable. - if (transform == null && ctx.beansRequireSerializable && ! isParentClass(Serializable.class, c)) - return "Class is not serializable"; - - // Look for @BeanConstructor constructor. - for (Constructor<?> x : c.getConstructors()) { - if (x.isAnnotationPresent(BeanConstructor.class)) { - if (constructor != null) - throw new BeanRuntimeException(c, "Multiple instances of '@BeanConstructor' found."); - constructor = (Constructor<T>)x; - constructorArgs = x.getAnnotation(BeanConstructor.class).properties(); - if (constructorArgs.length != x.getParameterTypes().length) - throw new BeanRuntimeException(c, "Number of properties defined in '@BeanConstructor' annotation does not match number of parameters in constructor."); - if (! setAccessible(constructor)) - throw new BeanRuntimeException(c, "Could not set accessibility to true on method with @BeanConstructor annotation. Method=''{0}''", constructor.getName()); - } - } - - // If this is an interface, look for impl classes defined in the context. - if (constructor == null) - constructor = (Constructor<T>)ctx.getImplClassConstructor(c, conVis); - - if (constructor == null) - constructor = (Constructor<T>)ClassMeta.findNoArgConstructor(c, conVis); - - if (constructor == null && transform == null && ctx.beansRequireDefaultConstructor) - return "Class does not have the required no-arg constructor"; - - if (! setAccessible(constructor)) - throw new BeanRuntimeException(c, "Could not set accessibility to true on no-arg constructor"); - - // Explicitly defined property names in @Bean annotation. - Set<String> fixedBeanProps = new LinkedHashSet<String>(); - - if (transform != null) { - - // Get the 'properties' attribute if specified. - if (transform.getProperties() != null) - for (String p : transform.getProperties()) - fixedBeanProps.add(p); - - if (transform.getPropertyNamer() != null) - propertyNamer = transform.getPropertyNamer().newInstance(); - } - - if (propertyNamer == null) - propertyNamer = new PropertyNamerDefault(); - - // First populate the properties with those specified in the bean annotation to - // ensure that ordering first. - for (String name : fixedBeanProps) - normalProps.put(name, new BeanPropertyMeta<T>(this, name)); - - if (ctx.useJavaBeanIntrospector) { - BeanInfo bi = null; - if (! c2.isInterface()) - bi = Introspector.getBeanInfo(c2, stopClass); - else - bi = Introspector.getBeanInfo(c2, null); - if (bi != null) { - for (PropertyDescriptor pd : bi.getPropertyDescriptors()) { - String name = pd.getName(); - if (! normalProps.containsKey(name)) - normalProps.put(name, new BeanPropertyMeta<T>(this, name)); - normalProps.get(name).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod()); - } - } - - } else /* Use 'better' introspection */ { - - for (Field f : findBeanFields(c2, stopClass, fVis)) { - String name = findPropertyName(f, fixedBeanProps); - if (name != null) { - if (! normalProps.containsKey(name)) - normalProps.put(name, new BeanPropertyMeta<T>(this, name)); - normalProps.get(name).setField(f); - } - } - - List<BeanMethod> bms = findBeanMethods(c2, stopClass, mVis, fixedBeanProps, propertyNamer); - - // Iterate through all the getters. - for (BeanMethod bm : bms) { - String pn = bm.propertyName; - Method m = bm.method; - if (! normalProps.containsKey(pn)) - normalProps.put(pn, new BeanPropertyMeta<T>(this, pn)); - BeanPropertyMeta<?> bpm = normalProps.get(pn); - if (! bm.isSetter) - bpm.setGetter(m); - } - - // Now iterate through all the setters. - for (BeanMethod bm : bms) { - if (bm.isSetter) { - BeanPropertyMeta<?> bpm = normalProps.get(bm.propertyName); - if (bm.matchesPropertyType(bpm)) - bpm.setSetter(bm.method); - } - } - } - - typeVarImpls = new HashMap<Class<?>,Class<?>[]>(); - findTypeVarImpls(c, typeVarImpls); - if (typeVarImpls.isEmpty()) - typeVarImpls = null; - - // Eliminate invalid properties, and set the contents of getterProps and setterProps. - for (Iterator<BeanPropertyMeta<T>> i = normalProps.values().iterator(); i.hasNext();) { - BeanPropertyMeta<T> p = i.next(); - try { - if (p.validate()) { - - if (p.getGetter() != null) - getterProps.put(p.getGetter(), p.getName()); - - if (p.getSetter() != null) - setterProps.put(p.getSetter(), p.getName()); - - if (p.isBeanUri()) - uriProperty = p; - - } else { - i.remove(); - } - } catch (ClassNotFoundException e) { - throw new BeanRuntimeException(c, e.getLocalizedMessage()); - } - } - - // Check for missing properties. - for (String fp : fixedBeanProps) - if (! normalProps.containsKey(fp)) - throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @Bean(properties=X) annotation but was not found on the class definition.", fp); - - // Mark constructor arg properties. - for (String fp : constructorArgs) { - BeanPropertyMeta<T> m = normalProps.get(fp); - if (m == null) - throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @BeanConstructor(properties=X) annotation but was not found on the class definition.", fp); - m.setAsConstructorArg(); - } - - // Make sure at least one property was found. - if (transform == null && ctx.beansRequireSomeProperties && normalProps.size() == 0) - return "No properties detected on bean class"; - - boolean sortProperties = (ctx.sortProperties || (transform != null && transform.isSortProperties())) && fixedBeanProps.isEmpty(); - - properties = sortProperties ? new TreeMap<String,BeanPropertyMeta<T>>() : new LinkedHashMap<String,BeanPropertyMeta<T>>(); - - if (transform != null && transform.getSubTypeProperty() != null) { - String subTypeProperty = transform.getSubTypeProperty(); - this.subTypeIdProperty = new SubTypePropertyMeta(subTypeProperty, transform.getSubTypes(), normalProps.remove(subTypeProperty)); - properties.put(subTypeProperty, this.subTypeIdProperty); - } - - properties.putAll(normalProps); - - // If a transform is defined, look for inclusion and exclusion lists. - if (transform != null) { - - // Eliminated excluded properties if BeanTransform.excludeKeys is specified. - String[] includeKeys = transform.getProperties(); - String[] excludeKeys = transform.getExcludeProperties(); - if (excludeKeys != null) { - for (String k : excludeKeys) - properties.remove(k); - - // Only include specified properties if BeanTransform.includeKeys is specified. - // Note that the order must match includeKeys. - } else if (includeKeys != null) { - Map<String,BeanPropertyMeta<T>> properties2 = new LinkedHashMap<String,BeanPropertyMeta<T>>(); - for (String k : includeKeys) { - if (properties.containsKey(k)) - properties2.put(k, properties.get(k)); - } - properties = properties2; - } - } - - xmlMeta = new XmlBeanMeta<T>(this, null); - - // We return this through the Bean.keySet() interface, so make sure it's not modifiable. - properties = Collections.unmodifiableMap(properties); - - } catch (BeanRuntimeException e) { - throw e; - } catch (Exception e) { - return "Exception: " + StringUtils.getStackTrace(e); - } - - return null; - } - - /** - * Returns the subtype ID property of this bean if it has one. - * <p> - * The subtype id is specified using the {@link Bean#subTypeProperty()} annotation. - * - * @return The meta property for the sub type property, or <jk>null</jk> if no subtype is defined for this bean. - */ - public BeanPropertyMeta<T> getSubTypeIdProperty() { - return subTypeIdProperty; - } - - /** - * Returns <jk>true</jk> if this bean has subtypes associated with it. - * Subtypes are defined using the {@link Bean#subTypes()} annotation. - * - * @return <jk>true</jk> if this bean has subtypes associated with it. - */ - public boolean isSubTyped() { - return subTypeIdProperty != null; - } - - /** - * Returns <jk>true</jk> if one of the properties on this bean is annotated with {@link BeanProperty#beanUri()} as <jk>true</jk> - * - * @return <jk>true</jk> if this bean has subtypes associated with it. <jk>true</jk> if there is a URI property associated with this bean. - */ - public boolean hasBeanUriProperty() { - return uriProperty != null; - } - - /** - * Returns the bean property marked as the URI for the bean (annotated with {@link BeanProperty#beanUri()} as <jk>true</jk>). - * - * @return The URI property, or <jk>null</jk> if no URI property exists on this bean. - */ - public BeanPropertyMeta<T> getBeanUriProperty() { - return uriProperty; - } - - /* - * Temporary getter/setter method struct. - */ - private static class BeanMethod { - String propertyName; - boolean isSetter; - Method method; - Class<?> type; - - BeanMethod(String propertyName, boolean isSetter, Method method) { - this.propertyName = propertyName; - this.isSetter = isSetter; - this.method = method; - if (isSetter) - this.type = method.getParameterTypes()[0]; - else - this.type = method.getReturnType(); - } - - /* - * Returns true if this method matches the class type of the specified property. - * Only meant to be used for setters. - */ - boolean matchesPropertyType(BeanPropertyMeta<?> b) { - if (b == null) - return false; - - // Get the bean property type from the getter/field. - Class<?> pt = null; - if (b.getGetter() != null) - pt = b.getGetter().getReturnType(); - else if (b.getField() != null) - pt = b.getField().getType(); - - // Doesn't match if no getter/field defined. - if (pt == null) - return false; - - // Doesn't match if not same type or super type as getter/field. - if (! isParentClass(type, pt)) - return false; - - // If a setter was previously set, only use this setter if it's a closer - // match (e.g. prev type is a superclass of this type). - if (b.getSetter() == null) - return true; - - Class<?> prevType = b.getSetter().getParameterTypes()[0]; - return isParentClass(prevType, type, true); - } - - @Override /* Object */ - public String toString() { - return method.toString(); - } - } - - /* - * Find all the bean methods on this class. - * - * @param c The transformed class. - * @param stopClass Don't look above this class in the hierarchy. - * @param v The minimum method visibility. - * @param fixedBeanProps Only include methods whose properties are in this list. - * @param pn Use this property namer to determine property names from the method names. - */ - private static List<BeanMethod> findBeanMethods(Class<?> c, Class<?> stopClass, Visibility v, Set<String> fixedBeanProps, PropertyNamer pn) { - List<BeanMethod> l = new LinkedList<BeanMethod>(); - - for (Class<?> c2 : findClasses(c, stopClass)) { - for (Method m : c2.getDeclaredMethods()) { - int mod = m.getModifiers(); - if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) - continue; - if (m.isAnnotationPresent(BeanIgnore.class)) - continue; - if (m.isBridge()) // This eliminates methods with covariant return types from parent classes on child classes. - continue; - if (! (v.isVisible(m) || m.isAnnotationPresent(BeanProperty.class))) - continue; - String n = m.getName(); - Class<?>[] pt = m.getParameterTypes(); - Class<?> rt = m.getReturnType(); - boolean isGetter = false, isSetter = false; - if (pt.length == 1 && n.startsWith("set") && (isParentClass(rt, c) || rt.equals(Void.TYPE))) { - isSetter = true; - n = n.substring(3); - } else if (pt.length == 0 && n.startsWith("get") && (! rt.equals(Void.TYPE))) { - isGetter = true; - n = n.substring(3); - } else if (pt.length == 0 && n.startsWith("is") && (rt.equals(Boolean.TYPE) || rt.equals(Boolean.class))) { - isGetter = true; - n = n.substring(2); - } - n = pn.getPropertyName(n); - if (isGetter || isSetter) { - BeanProperty bp = m.getAnnotation(BeanProperty.class); - if (bp != null && ! bp.name().equals("")) { - n = bp.name(); - if (! fixedBeanProps.isEmpty()) - if (! fixedBeanProps.contains(n)) - throw new BeanRuntimeException(c, "Method property ''{0}'' identified in @BeanProperty, but missing from @Bean", n); - } - l.add(new BeanMethod(n, isSetter, m)); - } - } - } - return l; - } - - private static Collection<Field> findBeanFields(Class<?> c, Class<?> stopClass, Visibility v) { - List<Field> l = new LinkedList<Field>(); - for (Class<?> c2 : findClasses(c, stopClass)) { - for (Field f : c2.getDeclaredFields()) { - int m = f.getModifiers(); - if (Modifier.isStatic(m) || Modifier.isTransient(m)) - continue; - if (f.isAnnotationPresent(BeanIgnore.class)) - continue; - if (! (v.isVisible(f) || f.isAnnotationPresent(BeanProperty.class))) - continue; - l.add(f); - } - } - return l; - } - - private static List<Class<?>> findClasses(Class<?> c, Class<?> stopClass) { - LinkedList<Class<?>> l = new LinkedList<Class<?>>(); - findClasses(c, l, stopClass); - return l; - } - - private static void findClasses(Class<?> c, LinkedList<Class<?>> l, Class<?> stopClass) { - while (c != null && stopClass != c) { - l.addFirst(c); - for (Class<?> ci : c.getInterfaces()) - findClasses(ci, l, stopClass); - c = c.getSuperclass(); - } - } - - /** - * Returns the metadata on all properties associated with this bean. - * - * @return Metadata on all properties associated with this bean. - */ - public Collection<BeanPropertyMeta<T>> getPropertyMetas() { - return this.properties.values(); - } - - /** - * Returns the metadata on the specified list of properties. - * - * @param pNames The list of properties to retrieve. If <jk>null</jk>, returns all properties. - * @return The metadata on the specified list of properties. - */ - public Collection<BeanPropertyMeta<T>> getPropertyMetas(final String...pNames) { - if (pNames == null) - return getPropertyMetas(); - List<BeanPropertyMeta<T>> l = new ArrayList<BeanPropertyMeta<T>>(pNames.length); - for (int i = 0; i < pNames.length; i++) - l.add(getPropertyMeta(pNames[i])); - return l; - } - - /** - * Returns XML related metadata for this bean type. - * - * @return The XML metadata for this bean type. - */ - public XmlBeanMeta<T> getXmlMeta() { - return xmlMeta; - } - - /** - * Returns metadata about the specified property. - * - * @param name The name of the property on this bean. - * @return The metadata about the property, or <jk>null</jk> if no such property exists - * on this bean. - */ - public BeanPropertyMeta<T> getPropertyMeta(String name) { - return this.properties.get(name); - } - - /** - * Creates a new instance of this bean. - * - * @param outer The outer object if bean class is a non-static inner member class. - * @return A new instance of this bean if possible, or <jk>null</jk> if not. - * @throws IllegalArgumentException Thrown by constructor. - * @throws InstantiationException Thrown by constructor. - * @throws IllegalAccessException Thrown by constructor. - * @throws InvocationTargetException Thrown by constructor. - */ - @SuppressWarnings("unchecked") - protected T newBean(Object outer) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { - if (classMeta.isMemberClass) { - if (constructor != null) - return constructor.newInstance(outer); - } else { - if (constructor != null) - return constructor.newInstance((Object[])null); - InvocationHandler h = classMeta.getProxyInvocationHandler(); - if (h != null) { - ClassLoader cl = classMeta.beanContext.classLoader; - if (cl == null) - cl = this.getClass().getClassLoader(); - return (T)Proxy.newProxyInstance(cl, new Class[] { classMeta.innerClass, java.io.Serializable.class }, h); - } - } - return null; - } - - /* - * Returns the property name of the specified field if it's a valid property. - * Returns null if the field isn't a valid property. - */ - private String findPropertyName(Field f, Set<String> fixedBeanProps) { - BeanProperty bp = f.getAnnotation(BeanProperty.class); - if (bp != null && ! bp.name().equals("")) { - String name = bp.name(); - if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name)) - return name; - throw new BeanRuntimeException(c, "Method property ''{0}'' identified in @BeanProperty, but missing from @Bean", name); - } - String name = propertyNamer.getPropertyName(f.getName()); - if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name)) - return name; - return null; - } - - /** - * Recursively determines the classes represented by parameterized types in the class hierarchy of - * the specified type, and puts the results in the specified map.<br> - * <p> - * For example, given the following classes... - * <p class='bcode'> - * public static class BeanA<T> { - * public T x; - * } - * public static class BeanB extends BeanA<Integer>} {...} - * <p> - * ...calling this method on {@code BeanB.class} will load the following data into {@code m} indicating - * that the {@code T} parameter on the BeanA class is implemented with an {@code Integer}: - * <p class='bcode'> - * {BeanA.class:[Integer.class]} - * <p> - * TODO: This code doesn't currently properly handle the following situation: - * <p class='bcode'> - * public static class BeanB<T extends Number> extends BeanA<T>; - * public static class BeanC extends BeanB<Integer>; - * <p> - * When called on {@code BeanC}, the variable will be detected as a {@code Number}, not an {@code Integer}.<br> - * If anyone can figure out a better way of doing this, please do so! - * - * @param t The type we're recursing. - * @param m Where the results are loaded. - */ - private static void findTypeVarImpls(Type t, Map<Class<?>,Class<?>[]> m) { - if (t instanceof Class) { - Class<?> c = (Class<?>)t; - findTypeVarImpls(c.getGenericSuperclass(), m); - for (Type ci : c.getGenericInterfaces()) - findTypeVarImpls(ci, m); - } else if (t instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType)t; - Type rt = pt.getRawType(); - if (rt instanceof Class) { - Type[] gImpls = pt.getActualTypeArguments(); - Class<?>[] gTypes = new Class[gImpls.length]; - for (int i = 0; i < gImpls.length; i++) { - Type gt = gImpls[i]; - if (gt instanceof Class) - gTypes[i] = (Class<?>)gt; - else if (gt instanceof TypeVariable) { - TypeVariable<?> tv = (TypeVariable<?>)gt; - for (Type upperBound : tv.getBounds()) - if (upperBound instanceof Class) - gTypes[i] = (Class<?>)upperBound; - } - } - m.put((Class<?>)rt, gTypes); - findTypeVarImpls(pt.getRawType(), m); - } - } - } - - /* - * Bean property for getting and setting bean subtype. - */ - @SuppressWarnings({"rawtypes","unchecked"}) - private class SubTypePropertyMeta extends BeanPropertyMeta<T> { - - private Map<Class<?>,String> subTypes; - private BeanPropertyMeta<T> realProperty; // Bean property if bean actually has a real subtype field. - - SubTypePropertyMeta(String subTypeAttr, Map<Class<?>,String> subTypes, BeanPropertyMeta<T> realProperty) { - super(BeanMeta.this, subTypeAttr, ctx.string()); - this.subTypes = subTypes; - this.realProperty = realProperty; - this.htmlMeta = new HtmlBeanPropertyMeta<T>(this); - this.xmlMeta = new XmlBeanPropertyMeta<T>(this); - this.rdfMeta = new RdfBeanPropertyMeta<T>(this); - } - - /* - * Setting this bean property causes the inner bean to be set to the subtype implementation. - */ - @Override /* BeanPropertyMeta */ - public Object set(BeanMap<T> m, Object value) throws BeanRuntimeException { - if (value == null) - throw new BeanRuntimeException("Attempting to set bean subtype property to null."); - String subTypeId = value.toString(); - for (Entry<Class<?>,String> e : subTypes.entrySet()) { - if (e.getValue().equals(subTypeId)) { - Class subTypeClass = e.getKey(); - m.meta = ctx.getBeanMeta(subTypeClass); - try { - m.bean = (T)subTypeClass.newInstance(); - if (realProperty != null) - realProperty.set(m, value); - // If subtype attribute wasn't specified first, set them again from the temporary cache. - if (m.propertyCache != null) - for (Map.Entry<String,Object> me : m.propertyCache.entrySet()) - m.put(me.getKey(), me.getValue()); - } catch (Exception e1) { - throw new BeanRuntimeException(e1); - } - return null; - } - } - throw new BeanRuntimeException(c, "Unknown subtype ID ''{0}''", subTypeId); - } - - @Override /* BeanPropertyMeta */ - public Object get(BeanMap<T> m) throws BeanRuntimeException { - String subTypeId = transform.getSubTypes().get(c); - if (subTypeId == null) - throw new BeanRuntimeException(c, "Unmapped sub type class"); - return subTypeId; - } - } - - @Override /* Object */ - public String toString() { - StringBuilder sb = new StringBuilder(c.getName()); - sb.append(" {\n"); - for (BeanPropertyMeta<?> pm : this.properties.values()) - sb.append('\t').append(pm.toString()).append(",\n"); - sb.append('}'); - return sb.toString(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2c3a7cb5/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMetaFiltered.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMetaFiltered.java b/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMetaFiltered.java deleted file mode 100644 index 09b0d0d..0000000 --- a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanMetaFiltered.java +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - ***************************************************************************************************************************/ -package org.apache.juneau; - -import java.util.*; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.xml.*; - -/** - * Sames as {@link BeanMeta}, except the list of bean properties are limited - * by a {@link BeanProperty#properties()} annotation. - * - * @param <T> The class type that this metadata applies to. - * @author James Bognar ([email protected]) - */ -public final class BeanMetaFiltered<T> extends BeanMeta<T> { - - private final BeanMeta<T> innerMeta; - - /** - * Wrapper constructor. - * - * @param innerMeta The untransformed bean meta of the bean property. - * @param pNames The list of transformed property names. - */ - public BeanMetaFiltered(BeanMeta<T> innerMeta, String[] pNames) { - this.innerMeta = innerMeta; - this.properties = new LinkedHashMap<String,BeanPropertyMeta<T>>(); - for (String p : pNames) - properties.put(p, innerMeta.getPropertyMeta(p)); - this.xmlMeta = new XmlBeanMeta<T>(innerMeta, pNames); - } - - /** - * Wrapper constructor. - * - * @param innerMeta The untransformed bean meta of the bean property. - * @param pNames The list of transformed property names. - */ - public BeanMetaFiltered(BeanMeta<T> innerMeta, Collection<String> pNames) { - this(innerMeta, pNames.toArray(new String[pNames.size()])); - } - - @Override /* Delagate */ - public ClassMeta<T> getClassMeta() { - return innerMeta.classMeta; - } - - @Override /* BeanMeta */ - public Collection<BeanPropertyMeta<T>> getPropertyMetas() { - return properties.values(); - } - - @Override /* BeanMeta */ - public BeanPropertyMeta<T> getPropertyMeta(String name) { - return properties.get(name); - } - - @Override /* Object */ - public String toString() { - return innerMeta.c.getName(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2c3a7cb5/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanPropertyMeta.java ---------------------------------------------------------------------- diff --git a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanPropertyMeta.java deleted file mode 100644 index e72ff21..0000000 --- a/com.ibm.team.juno/src/main/java/org/apache/juneau/BeanPropertyMeta.java +++ /dev/null @@ -1,807 +0,0 @@ -/*************************************************************************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - ***************************************************************************************************************************/ -package org.apache.juneau; - -import static org.apache.juneau.Visibility.*; -import static org.apache.juneau.internal.ClassUtils.*; -import static org.apache.juneau.internal.CollectionUtils.*; -import static org.apache.juneau.internal.ReflectionUtils.*; - -import java.lang.annotation.*; -import java.lang.reflect.*; -import java.net.*; -import java.net.URI; -import java.util.*; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.html.*; -import org.apache.juneau.internal.*; -import org.apache.juneau.jena.*; -import org.apache.juneau.parser.*; -import org.apache.juneau.serializer.*; -import org.apache.juneau.transform.*; -import org.apache.juneau.xml.*; - -/** - * Contains metadata about a bean property. - * <p> - * Contains information such as type of property (e.g. field/getter/setter), class type of property value, - * and whether any transforms are associated with this property. - * <p> - * Developers will typically not need access to this class. The information provided by it is already - * exposed through several methods on the {@link BeanMap} API. - * - * @param <T> The class type of the bean that this metadata applies to. - * @author James Bognar ([email protected]) - */ -@SuppressWarnings({ "rawtypes", "unchecked" }) -public class BeanPropertyMeta<T> { - - private Field field; - private Method getter, setter; - private boolean isConstructorArg, isBeanUri, isUri; - - private final BeanMeta<T> beanMeta; - - private String name; - private ClassMeta<?> - rawTypeMeta, // The real class type of the bean property. - typeMeta; // The transformed class type of the bean property. - private String[] properties; - private PojoTransform transform; // PojoTransform defined only via @BeanProperty annotation. - - /** HTML related metadata on this bean property. */ - protected HtmlBeanPropertyMeta<T> htmlMeta; - - /** XML related metadata on this bean property. */ - protected XmlBeanPropertyMeta<T> xmlMeta; - - /** RDF related metadata on this bean property. */ - protected RdfBeanPropertyMeta<T> rdfMeta; // - - BeanPropertyMeta(BeanMeta<T> beanMeta, String name) { - this.beanMeta = beanMeta; - this.name = name; - } - - BeanPropertyMeta(BeanMeta<T> beanMeta, String name, ClassMeta<?> rawTypeMeta) { - this(beanMeta, name); - this.rawTypeMeta = rawTypeMeta; - } - - BeanPropertyMeta(BeanMeta<T> beanMeta, String name, Method getter, Method setter) { - this(beanMeta, name); - setGetter(getter); - setSetter(setter); - } - - /** - * Returns the name of this bean property. - * - * @return The name of the bean property. - */ - public String getName() { - return name; - } - - /** - * Returns the bean meta that this property belongs to. - * - * @return The bean meta that this property belongs to. - */ - @BeanIgnore - public BeanMeta<T> getBeanMeta() { - return beanMeta; - } - - /** - * Returns the getter method for this property. - * - * @return The getter method for this bean property, or <jk>null</jk> if there is no getter method. - */ - public Method getGetter() { - return getter; - } - - /** - * Returns the setter method for this property. - * - * @return The setter method for this bean property, or <jk>null</jk> if there is no setter method. - */ - public Method getSetter() { - return setter; - } - - /** - * Returns the field for this property. - * - * @return The field for this bean property, or <jk>null</jk> if there is no field associated with this bean property. - */ - public Field getField() { - return field; - } - - /** - * Returns the {@link ClassMeta} of the class of this property. - * <p> - * If this property or the property type class has a {@link PojoTransform} associated with it, this - * method returns the transformed class meta. - * This matches the class type that is used by the {@link #get(BeanMap)} and {@link #set(BeanMap, Object)} methods. - * - * @return The {@link ClassMeta} of the class of this property. - */ - public ClassMeta<?> getClassMeta() { - if (typeMeta == null) - typeMeta = (transform != null ? transform.getTransformedClassMeta() : rawTypeMeta.getTransformedClassMeta()); - return typeMeta; - } - - /** - * Sets the getter method for this property. - * - * @param getter The getter method to associate with this property. - * @return This object (for method chaining). - */ - BeanPropertyMeta<T> setGetter(Method getter) { - setAccessible(getter); - this.getter = getter; - return this; - } - - /** - * Sets the setter method for this property. - * - * @param setter The setter method to associate with this property. - * @return This object (for method chaining). - */ - BeanPropertyMeta<T> setSetter(Method setter) { - setAccessible(setter); - this.setter = setter; - return this; - } - - /** - * Sets the field for this property. - * - * @param field The field to associate with this property. - * @return This object (for method chaining). - */ - BeanPropertyMeta<T> setField(Field field) { - setAccessible(field); - this.field = field; - return this; - } - - /** - * Marks this property as only settable through a constructor arg. - * - * @return This object (for method chaining). - */ - BeanPropertyMeta<T> setAsConstructorArg() { - this.isConstructorArg = true; - return this; - } - - /** - * Returns <jk>true</jk> if this bean property is marked with {@link BeanProperty#beanUri()} as <jk>true</jk>. - * - * @return <jk>true</jk> if this bean property is marked with {@link BeanProperty#beanUri()} as <jk>true</jk>. - */ - public boolean isBeanUri() { - return isBeanUri; - } - - /** - * Returns <jk>true</jk> if this bean property is a URI. - * <p> - * A bean property can be considered a URI if any of the following are true: - * <ul class='spaced-list'> - * <li>Property class type is {@link URL} or {@link URI}. - * <li>Property class type is annotated with {@link org.apache.juneau.annotation.URI}. - * <li>Property getter, setter, or field is annotated with {@link org.apache.juneau.annotation.URI}. - * </ul> - * - * @return <jk>true</jk> if this bean property is a URI. - */ - public boolean isUri() { - return isUri; - } - - /** - * Returns the override list of properties defined through a {@link BeanProperty#properties()} annotation - * on this property. - * - * @return The list of override properties, or <jk>null</jk> if annotation not specified. - */ - public String[] getProperties() { - return properties; - } - - /** - * Returns the HTML-related metadata on this bean property. - * - * @return The HTML-related metadata on this bean property. Never <jk>null</jk>/. - */ - public HtmlBeanPropertyMeta<T> getHtmlMeta() { - return htmlMeta; - } - - /** - * Returns the XML-related metadata on this bean property. - * - * @return The XML-related metadata on this bean property. Never <jk>null</jk>/. - */ - public XmlBeanPropertyMeta<T> getXmlMeta() { - return xmlMeta; - } - - /** - * Returns the RDF-related metadata on this bean property. - * - * @return The RDF-related metadata on this bean property. Never <jk>null</jk>/. - */ - public RdfBeanPropertyMeta<T> getRdfMeta() { - return rdfMeta; - } - - boolean validate() throws Exception { - - BeanContext f = beanMeta.ctx; - Map<Class<?>,Class<?>[]> typeVarImpls = beanMeta.typeVarImpls; - - if (field == null && getter == null) - return false; - - if (field == null && setter == null && f.beansRequireSettersForGetters && ! isConstructorArg) - return false; - - if (field != null) { - BeanProperty p = field.getAnnotation(BeanProperty.class); - rawTypeMeta = f.getClassMeta(p, field.getGenericType(), typeVarImpls); - isUri |= (rawTypeMeta.isUri() || field.isAnnotationPresent(org.apache.juneau.annotation.URI.class)); - if (p != null) { - transform = getPropertyPojoTransform(p); - if (p.properties().length != 0) - properties = p.properties(); - isBeanUri |= p.beanUri(); - } - } - - if (getter != null) { - BeanProperty p = getter.getAnnotation(BeanProperty.class); - if (rawTypeMeta == null) - rawTypeMeta = f.getClassMeta(p, getter.getGenericReturnType(), typeVarImpls); - isUri |= (rawTypeMeta.isUri() || getter.isAnnotationPresent(org.apache.juneau.annotation.URI.class)); - if (p != null) { - if (transform == null) - transform = getPropertyPojoTransform(p); - if (properties != null && p.properties().length != 0) - properties = p.properties(); - isBeanUri |= p.beanUri(); - } - } - - if (setter != null) { - BeanProperty p = setter.getAnnotation(BeanProperty.class); - if (rawTypeMeta == null) - rawTypeMeta = f.getClassMeta(p, setter.getGenericParameterTypes()[0], typeVarImpls); - isUri |= (rawTypeMeta.isUri() || setter.isAnnotationPresent(org.apache.juneau.annotation.URI.class)); - if (p != null) { - if (transform == null) - transform = getPropertyPojoTransform(p); - if (properties != null && p.properties().length != 0) - properties = p.properties(); - isBeanUri |= p.beanUri(); - } - } - - if (rawTypeMeta == null) - return false; - - // Do some annotation validation. - Class<?> c = rawTypeMeta.getInnerClass(); - if (getter != null && ! isParentClass(getter.getReturnType(), c)) - return false; - if (setter != null && ! isParentClass(setter.getParameterTypes()[0], c)) - return false; - if (field != null && ! isParentClass(field.getType(), c)) - return false; - - htmlMeta = new HtmlBeanPropertyMeta(this); - xmlMeta = new XmlBeanPropertyMeta(this); - rdfMeta = new RdfBeanPropertyMeta(this); - - return true; - } - - private PojoTransform getPropertyPojoTransform(BeanProperty p) throws Exception { - Class<? extends PojoTransform> c = p.transform(); - if (c == PojoTransform.NULL.class) - return null; - try { - PojoTransform f = c.newInstance(); - f.setBeanContext(this.beanMeta.ctx); - return f; - } catch (Exception e) { - throw new BeanRuntimeException(this.beanMeta.c, "Could not instantiate PojoTransform ''{0}'' for bean property ''{1}''", c.getName(), this.name).initCause(e); - } - } - - /** - * Equivalent to calling {@link BeanMap#get(Object)}, but is faster since it avoids looking up the property meta. - * - * @param m The bean map to get the transformed value from. - * @return The property value. - */ - public Object get(BeanMap<T> m) { - try { - // Read-only beans have their properties stored in a cache until getBean() is called. - Object bean = m.bean; - if (bean == null) - return m.propertyCache.get(name); - - Object o = null; - - if (getter == null && field == null) - throw new BeanRuntimeException(beanMeta.c, "Getter or public field not defined on property ''{0}''", name); - - if (getter != null) - o = getter.invoke(bean, (Object[])null); - - else if (field != null) - o = field.get(bean); - - o = transform(o); - if (o == null) - return null; - if (properties != null) { - if (rawTypeMeta.isArray()) { - Object[] a = (Object[])o; - List l = new ArrayList(a.length); - ClassMeta childType = rawTypeMeta.getElementType(); - for (Object c : a) - l.add(applyChildPropertiesFilter(childType, c)); - return l; - } else if (rawTypeMeta.isCollection()) { - Collection c = (Collection)o; - List l = new ArrayList(c.size()); - ClassMeta childType = rawTypeMeta.getElementType(); - for (Object cc : c) - l.add(applyChildPropertiesFilter(childType, cc)); - return l; - } else { - return applyChildPropertiesFilter(rawTypeMeta, o); - } - } - return o; - } catch (SerializeException e) { - throw new BeanRuntimeException(e); - } catch (Throwable e) { - if (beanMeta.ctx.ignoreInvocationExceptionsOnGetters) { - if (rawTypeMeta.isPrimitive()) - return rawTypeMeta.getPrimitiveDefault(); - return null; - } - throw new BeanRuntimeException(beanMeta.c, "Exception occurred while getting property ''{0}''", name).initCause(e); - } - } - - /** - * Equivalent to calling {@link BeanMap#put(String, Object)}, but is faster since it avoids - * looking up the property meta. - * - * @param m The bean map to set the property value on. - * @param value The value to set. - * @return The previous property value. - * @throws BeanRuntimeException If property could not be set. - */ - public Object set(BeanMap<T> m, Object value) throws BeanRuntimeException { - try { - // Comvert to raw form. - value = normalize(value); - BeanContext bc = this.beanMeta.ctx; - - if (m.bean == null) { - - // If this bean has subtypes, and we haven't set the subtype yet, - // store the property in a temporary cache until the bean can be instantiated. - if (m.meta.subTypeIdProperty != null && m.propertyCache == null) - m.propertyCache = new TreeMap<String,Object>(); - - // Read-only beans get their properties stored in a cache. - if (m.propertyCache != null) - return m.propertyCache.put(name, value); - - throw new BeanRuntimeException("Non-existent bean instance on bean."); - } - - boolean isMap = rawTypeMeta.isMap(); - boolean isCollection = rawTypeMeta.isCollection(); - - if (field == null && setter == null && ! (isMap || isCollection)) { - if ((value == null && bc.ignoreUnknownNullBeanProperties) || bc.ignorePropertiesWithoutSetters) - return null; - throw new BeanRuntimeException(beanMeta.c, "Setter or public field not defined on property ''{0}''", name); - } - - Object bean = m.getBean(true); // Don't use getBean() because it triggers array creation! - - try { - - Object r = beanMeta.ctx.beanMapPutReturnsOldValue || isMap || isCollection ? get(m) : null; - Class<?> propertyClass = rawTypeMeta.getInnerClass(); - - if (value == null && (isMap || isCollection)) { - if (setter != null) { - setter.invoke(bean, new Object[] { null }); - return r; - } else if (field != null) { - field.set(bean, null); - return r; - } - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' to null because no setter or public field is defined", name); - } - - if (isMap) { - - if (! (value instanceof Map)) { - if (value instanceof CharSequence) - value = new ObjectMap((CharSequence)value).setBeanContext(beanMeta.ctx); - else - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), findClassName(value)); - } - - Map valueMap = (Map)value; - Map propMap = (Map)r; - ClassMeta<?> valueType = rawTypeMeta.getValueType(); - - // If the property type is abstract, then we either need to reuse the existing - // map (if it's not null), or try to assign the value directly. - if (! rawTypeMeta.canCreateNewInstance()) { - if (propMap == null) { - if (setter == null && field == null) - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name, propertyClass.getName(), findClassName(value)); - - if (propertyClass.isInstance(valueMap)) { - if (! valueType.isObject()) { - for (Map.Entry e : (Set<Map.Entry>)valueMap.entrySet()) { - Object v = e.getValue(); - if (v != null && ! valueType.getInnerClass().isInstance(v)) - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because the value types in the assigned map do not match the specified ''elementClass'' attribute on the property, and the property value is currently null", name, propertyClass.getName(), findClassName(value)); - } - } - if (setter != null) - setter.invoke(bean, valueMap); - else - field.set(bean, valueMap); - return r; - } - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{2}'' to object of type ''{2}'' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null", name, propertyClass.getName(), findClassName(value)); - } - } else { - if (propMap == null) { - propMap = (Map)propertyClass.newInstance(); - if (setter != null) - setter.invoke(bean, propMap); - else if (field != null) - field.set(bean, propMap); - else - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined on this property, and the existing property value is null", name, propertyClass.getName(), findClassName(value)); - } else { - propMap.clear(); - } - } - - // Set the values. - for (Map.Entry e : (Set<Map.Entry>)valueMap.entrySet()) { - Object k = e.getKey(); - Object v = e.getValue(); - if (! valueType.isObject()) - v = beanMeta.ctx.convertToType(v, valueType); - propMap.put(k, v); - } - - } else if (isCollection) { - - if (! (value instanceof Collection)) { - if (value instanceof CharSequence) - value = new ObjectList((CharSequence)value).setBeanContext(beanMeta.ctx); - else - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), findClassName(value)); - } - - Collection valueList = (Collection)value; - Collection propList = (Collection)r; - ClassMeta elementType = rawTypeMeta.getElementType(); - - // If the property type is abstract, then we either need to reuse the existing - // collection (if it's not null), or try to assign the value directly. - if (! rawTypeMeta.canCreateNewInstance()) { - if (propList == null) { - if (setter == null && field == null) - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name, propertyClass.getName(), findClassName(value)); - - if (propertyClass.isInstance(valueList)) { - if (! elementType.isObject()) { - List l = new ObjectList(valueList); - for (ListIterator<Object> i = l.listIterator(); i.hasNext(); ) { - Object v = i.next(); - if (v != null && (! elementType.getInnerClass().isInstance(v))) { - i.set(bc.convertToType(v, elementType)); - } - } - valueList = l; - } - if (setter != null) - setter.invoke(bean, valueList); - else - field.set(bean, valueList); - return r; - } - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null", name, propertyClass.getName(), findClassName(value)); - } - propList.clear(); - } else { - if (propList == null) { - propList = (Collection)propertyClass.newInstance(); - if (setter != null) - setter.invoke(bean, propList); - else if (field != null) - field.set(bean, propList); - else - throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter is defined on this property, and the existing property value is null", name, propertyClass.getName(), findClassName(value)); - } else { - propList.clear(); - } - } - - // Set the values. - for (Object v : valueList) { - if (! elementType.isObject()) - v = beanMeta.ctx.convertToType(v, elementType); - propList.add(v); - } - - } else { - if (transform != null && value != null && isParentClass(transform.getTransformedClass(), value.getClass())) { - value = transform.normalize(value, rawTypeMeta); - } else { - value = beanMeta.ctx.convertToType(value, rawTypeMeta); - } - if (setter != null) - setter.invoke(bean, new Object[] { value }); - else if (field != null) - field.set(bean, value); - } - - return r; - - } catch (BeanRuntimeException e) { - throw e; - } catch (Exception e) { - if (beanMeta.ctx.ignoreInvocationExceptionsOnSetters) { - if (rawTypeMeta.isPrimitive()) - return rawTypeMeta.getPrimitiveDefault(); - return null; - } - throw new BeanRuntimeException(beanMeta.c, "Error occurred trying to set property ''{0}''", name).initCause(e); - } - } catch (ParseException e) { - throw new BeanRuntimeException(e); - } - } - - /** - * Sets an array field on this bean. - * Works on both <code>Object</code> and primitive arrays. - * - * @param bean The bean of the field. - * @param l The collection to use to set the array field. - * @throws IllegalArgumentException Thrown by method invocation. - * @throws IllegalAccessException Thrown by method invocation. - * @throws InvocationTargetException Thrown by method invocation. - */ - protected void setArray(T bean, List l) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { - Object array = ArrayUtils.toArray(l, this.rawTypeMeta.getElementType().getInnerClass()); - if (setter != null) - setter.invoke(bean, array); - else if (field != null) - field.set(bean, array); - else - throw new BeanRuntimeException(beanMeta.c, "Attempt to initialize array property ''{0}'', but no setter or field defined.", name); - } - - /** - * Adds a value to a {@link Collection} or array property. - * Note that adding values to an array property is inefficient for large - * arrays since it must copy the array into a larger array on each operation. - * - * @param m The bean of the field being set. - * @param value The value to add to the field. - * @throws BeanRuntimeException If field is not a collection or array. - */ - public void add(BeanMap<T> m, Object value) throws BeanRuntimeException { - - BeanContext bc = beanMeta.ctx; - - // Read-only beans get their properties stored in a cache. - if (m.bean == null) { - if (! m.propertyCache.containsKey(name)) - m.propertyCache.put(name, new ObjectList(bc)); - ((ObjectList)m.propertyCache.get(name)).add(value); - return; - } - - boolean isCollection = rawTypeMeta.isCollection(); - boolean isArray = rawTypeMeta.isArray(); - - if (! (isCollection || isArray)) - throw new BeanRuntimeException(beanMeta.c, "Attempt to add element to property ''{0}'' which is not a collection or array", name); - - Object bean = m.getBean(true); - - ClassMeta<?> elementType = rawTypeMeta.getElementType(); - - try { - Object v = bc.convertToType(value, elementType); - - if (isCollection) { - Collection c = null; - if (getter != null) { - c = (Collection)getter.invoke(bean, (Object[])null); - } else if (field != null) { - c = (Collection)field.get(bean); - } else { - throw new BeanRuntimeException(beanMeta.c, "Attempt to append to collection property ''{0}'', but no getter or field defined.", name); - } - - if (c != null) { - c.add(v); - return; - } - - if (rawTypeMeta.canCreateNewInstance()) - c = (Collection)rawTypeMeta.newInstance(); - else - c = new ObjectList(bc); - - c.add(v); - - if (setter != null) - setter.invoke(bean, c); - else if (field != null) - field.set(bean, c); - else - throw new BeanRuntimeException(beanMeta.c, "Attempt to initialize collection property ''{0}'', but no setter or field defined.", name); - - } else /* isArray() */ { - - if (m.arrayPropertyCache == null) - m.arrayPropertyCache = new TreeMap<String,List<?>>(); - - List l = m.arrayPropertyCache.get(name); - if (l == null) { - l = new LinkedList(); // ArrayLists and LinkLists appear to perform equally. - m.arrayPropertyCache.put(name, l); - - // Copy any existing array values into the temporary list. - Object oldArray; - if (getter != null) - oldArray = getter.invoke(bean, (Object[])null); - else if (field != null) - oldArray = field.get(bean); - else - throw new BeanRuntimeException(beanMeta.c, "Attempt to append to array property ''{0}'', but no getter or field defined.", name); - ArrayUtils.copyToList(oldArray, l); - } - - // Add new entry to our array. - l.add(v); - } - - } catch (BeanRuntimeException e) { - throw e; - } catch (Exception e) { - throw new BeanRuntimeException(e); - } - } - - /** - * Returns all instances of the specified annotation in the hierarchy of this bean property. - * <p> - * Searches through the class hierarchy (e.g. superclasses, interfaces, packages) for all - * instances of the specified annotation. - * - * @param a The class to find annotations for. - * @return A list of annotations ordered in child-to-parent order. Never <jk>null</jk>. - */ - public <A extends Annotation> List<A> findAnnotations(Class<A> a) { - List<A> l = new LinkedList<A>(); - if (field != null) { - addIfNotNull(l, field.getAnnotation(a)); - appendAnnotations(a, field.getType(), l); - } - if (getter != null) { - addIfNotNull(l, getter.getAnnotation(a)); - appendAnnotations(a, getter.getReturnType(), l); - } - if (setter != null) { - addIfNotNull(l, setter.getAnnotation(a)); - appendAnnotations(a, setter.getReturnType(), l); - } - appendAnnotations(a, this.getBeanMeta().getClassMeta().getInnerClass(), l); - return l; - } - - private Object transform(Object o) throws SerializeException { - // First use transform defined via @BeanProperty. - if (transform != null) - return transform.transform(o); - if (o == null) - return null; - // Otherwise, look it up via bean context. - if (rawTypeMeta.hasChildPojoTransforms()) { - Class c = o.getClass(); - ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanMeta.ctx.getClassMeta(c); - PojoTransform f = cm.getPojoTransform(); - if (f != null) - return f.transform(o); - } - return o; - } - - private Object normalize(Object o) throws ParseException { - if (transform != null) - return transform.normalize(o, rawTypeMeta); - if (o == null) - return null; - if (rawTypeMeta.hasChildPojoTransforms()) { - Class c = o.getClass(); - ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanMeta.ctx.getClassMeta(c); - PojoTransform f = cm.getPojoTransform(); - if (f != null) - return f.normalize(o, rawTypeMeta); - } - return o; - } - - private Object applyChildPropertiesFilter(ClassMeta cm, Object o) { - if (o == null) - return null; - if (cm.isBean()) - return new BeanMap(o, new BeanMetaFiltered(cm.getBeanMeta(), properties)); - if (cm.isMap()) - return new FilteredMap((Map)o, properties); - if (cm.isObject()) { - if (o instanceof Map) - return new FilteredMap((Map)o, properties); - BeanMeta bm = this.getBeanMeta().ctx.getBeanMeta(o.getClass()); - if (bm != null) - return new BeanMap(o, new BeanMetaFiltered(cm.getBeanMeta(), properties)); - } - return o; - } - - private String findClassName(Object o) { - if (o == null) - return null; - if (o instanceof Class) - return ((Class<?>)o).getName(); - return o.getClass().getName(); - } - - @Override /* Object */ - public String toString() { - return name + ": " + this.rawTypeMeta.getInnerClass().getName() + ", field=["+field+"], getter=["+getter+"], setter=["+setter+"]"; - } -}
