You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2016/08/01 16:03:20 UTC
[15/51] [abbrv] [partial] incubator-juneau git commit: Merge changes
from GitHub repo.
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 (james.bognar@salesforce.com)
- * @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 (james.bognar@salesforce.com)
- *
- * @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 (james.bognar@salesforce.com)
- */
-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 (james.bognar@salesforce.com)
- */
-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 (james.bognar@salesforce.com)
- */
-@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+"]";
- }
-}