blob: c8760f0f878cc8c00fbbf569922b3fba1ff3e506 [file] [log] [blame]
// ***************************************************************************************************************************
// * 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.internal.StringUtils.*;
import static org.apache.juneau.internal.ThrowableUtils.*;
import static org.apache.juneau.BeanContext.*;
import java.io.*;
import java.lang.reflect.*;
import java.time.*;
import java.util.*;
import java.util.Date;
import java.util.concurrent.atomic.*;
import org.apache.juneau.http.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.reflect.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.transform.*;
/**
* Session object that lives for the duration of a single use of {@link Serializer} or {@link Parser}.
*
* <p>
* This class is NOT thread safe. It is meant to be discarded after one-time use.
*/
@SuppressWarnings({"unchecked","rawtypes"})
public class BeanSession extends Session {
private final BeanContext ctx;
private final Locale locale;
private final TimeZone timeZone;
private final MediaType mediaType;
private final boolean debug;
private final HttpPartSchema schema;
private Stack<StringBuilder> sbStack = new Stack<>();
/**
* Create a new session using properties specified in the context.
*
* @param ctx
* The context creating this session object.
* The context contains all the configuration settings for this object.
* @param args
* Runtime session arguments.
*/
protected BeanSession(BeanContext ctx, BeanSessionArgs args) {
super(args);
this.ctx = ctx;
locale = getProperty(BEAN_locale, Locale.class, ctx.getLocale());
timeZone = getProperty(BEAN_timeZone, TimeZone.class, ctx.getTimeZone());
debug = getProperty(BEAN_debug, Boolean.class, ctx.isDebug());
mediaType = getProperty(BEAN_mediaType, MediaType.class, ctx.getMediaType());
schema = args.schema;
}
/**
* Converts the specified value to the specified class type.
*
* <p>
* See {@link #convertToType(Object, ClassMeta)} for the list of valid conversions.
*
* @param <T> The class type to convert the value to.
* @param value The value to convert.
* @param type The class type to convert the value to.
* @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
* @return The converted value.
*/
public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException {
// Shortcut for most common case.
if (value != null && value.getClass() == type)
return (T)value;
return convertToMemberType(null, value, getClassMeta(type));
}
/**
* Same as {@link #convertToType(Object, Class)}, except used for instantiating inner member classes that must
* be instantiated within another class instance.
*
* @param <T> The class type to convert the value to.
* @param outer
* If class is a member class, this is the instance of the containing class.
* Should be <jk>null</jk> if not a member class.
* @param value The value to convert.
* @param type The class type to convert the value to.
* @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
* @return The converted value.
*/
public final <T> T convertToMemberType(Object outer, Object value, Class<T> type) throws InvalidDataConversionException {
return convertToMemberType(outer, value, getClassMeta(type));
}
/**
* Casts the specified value into the specified type.
*
* <p>
* If the value isn't an instance of the specified type, then converts the value if possible.
*
* <p>
* The following conversions are valid:
* <table class='styled'>
* <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
* <tr>
* <td>
* A class that is the normal type of a registered {@link PojoSwap}.
* </td>
* <td>
* A value whose class matches the transformed type of that registered {@link PojoSwap}.
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* A class that is the transformed type of a registered {@link PojoSwap}.
* </td>
* <td>
* A value whose class matches the normal type of that registered {@link PojoSwap}.
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
* <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
* <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
* </td>
* <td>
* {@code Number}, {@code String}, <jk>null</jk>
* </td>
* <td>
* For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
* </td>
* </tr>
* <tr>
* <td>
* {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code ObjectMap})
* </td>
* <td>
* {@code Map}
* </td>
* <td>
* If {@code Map} is not constructible, a {@code ObjectMap} is created.
* </td>
* </tr>
* <tr>
* <td>
* {@code Collection} (e.g. {@code List}, {@code LinkedList}, {@code HashSet}, {@code ObjectList})
* </td>
* <td>
* {@code Collection<Object>}
* <br>{@code Object[]}
* </td>
* <td>
* If {@code Collection} is not constructible, a {@code ObjectList} is created.
* </td>
* </tr>
* <tr>
* <td>
* {@code X[]} (array of any type X)
* </td>
* <td>
* {@code List<X>}
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* {@code X[][]} (multi-dimensional arrays)
* </td>
* <td>
* {@code List<List<X>>}
* <br>{@code List<X[]>}
* <br>{@code List[]<X>}
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* {@code Enum}
* </td>
* <td>
* {@code String}
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* Bean
* </td>
* <td>
* {@code Map}
* </td>
* <td>&nbsp;</td>
* </tr>
* <tr>
* <td>
* {@code String}
* </td>
* <td>
* Anything
* </td>
* <td>
* Arrays are converted to JSON arrays
* </td>
* </tr>
* <tr>
* <td>
* Anything with one of the following methods:
* <br><code><jk>public static</jk> T fromString(String)</code>
* <br><code><jk>public static</jk> T valueOf(String)</code>
* <br><code><jk>public</jk> T(String)</code>
* </td>
* <td>
* <c>String</c>
* </td>
* <td>
* <br>
* </td>
* </tr>
* </table>
*
* @param <T> The class type to convert the value to.
* @param value The value to be converted.
* @param type The target object type.
* @return The converted type.
* @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
*/
public final <T> T convertToType(Object value, ClassMeta<T> type) throws InvalidDataConversionException {
return convertToMemberType(null, value, type);
}
/**
* Same as {@link #convertToType(Object, Class)}, but allows for complex data types consisting of collections or maps.
*
* @param <T> The class type to convert the value to.
* @param value The value to be converted.
* @param type The target object type.
* @param args The target object parameter types.
* @return The converted type.
* @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
*/
public final <T> T convertToType(Object value, Type type, Type...args) throws InvalidDataConversionException {
return (T)convertToMemberType(null, value, getClassMeta(type, args));
}
/**
* Same as {@link #convertToType(Object, ClassMeta)}, except used for instantiating inner member classes that must
* be instantiated within another class instance.
*
* @param <T> The class type to convert the value to.
* @param outer
* If class is a member class, this is the instance of the containing class.
* Should be <jk>null</jk> if not a member class.
* @param value The value to convert.
* @param to The class type to convert the value to.
* @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
* @return The converted value.
*/
protected final <T> T convertToMemberType(Object outer, Object value, ClassMeta<T> to) throws InvalidDataConversionException {
if (to == null)
to = (ClassMeta<T>)object();
try {
// Handle the case of a null value.
if (value == null) {
// If it's a primitive, then use the converters to get the default value for the primitive type.
if (to.isPrimitive())
return to.getPrimitiveDefault();
// Otherwise, just return null.
return to.isOptional() ? (T)to.getOptionalDefault() : null;
}
if (to.isOptional() && (! (value instanceof Optional)))
return (T) Optional.ofNullable(convertToMemberType(outer, value, to.getElementType()));
Class<T> tc = to.getInnerClass();
// If no conversion needed, then just return the value.
// Don't include maps or collections, because child elements may need conversion.
if (tc.isInstance(value))
if (! ((to.isMap() && to.getValueType().isNotObject()) || ((to.isCollection() || to.isOptional()) && to.getElementType().isNotObject())))
return (T)value;
PojoSwap swap = to.getPojoSwap(this);
if (swap != null) {
ClassInfo nc = swap.getNormalClass(), fc = swap.getSwapClass();
if (nc.isParentOf(tc) && fc.isParentOf(value.getClass()))
return (T)swap.unswap(this, value, to);
ClassMeta fcm = getClassMeta(fc.inner());
if (fcm.isNumber() && value instanceof Number) {
value = convertToMemberType(null, value, fc.inner());
return (T)swap.unswap(this, value, to);
}
}
ClassMeta<?> from = getClassMetaForObject(value);
swap = from.getPojoSwap(this);
if (swap != null) {
ClassInfo nc = swap.getNormalClass(), fc = swap.getSwapClass();
if (nc.isParentOf(from.getInnerClass()) && fc.isParentOf(tc))
return (T)swap.swap(this, value);
}
if (to.isPrimitive()) {
if (to.isNumber()) {
if (from.isNumber()) {
Number n = (Number)value;
if (tc == Integer.TYPE)
return (T)Integer.valueOf(n.intValue());
if (tc == Short.TYPE)
return (T)Short.valueOf(n.shortValue());
if (tc == Long.TYPE)
return (T)Long.valueOf(n.longValue());
if (tc == Float.TYPE)
return (T)Float.valueOf(n.floatValue());
if (tc == Double.TYPE)
return (T)Double.valueOf(n.doubleValue());
if (tc == Byte.TYPE)
return (T)Byte.valueOf(n.byteValue());
} else if (from.isBoolean()) {
Boolean b = (Boolean)value;
if (tc == Integer.TYPE)
return (T)(Integer.valueOf(b ? 1 : 0));
if (tc == Short.TYPE)
return (T)(Short.valueOf(b ? (short)1 : 0));
if (tc == Long.TYPE)
return (T)(Long.valueOf(b ? 1l : 0));
if (tc == Float.TYPE)
return (T)(Float.valueOf(b ? 1f : 0));
if (tc == Double.TYPE)
return (T)(Double.valueOf(b ? 1d : 0));
if (tc == Byte.TYPE)
return (T)(Byte.valueOf(b ? (byte)1 : 0));
} else if (isNullOrEmpty(value)) {
return (T)to.info.getPrimitiveDefault();
} else {
String s = value.toString();
int multiplier = (tc == Integer.TYPE || tc == Short.TYPE || tc == Long.TYPE) ? getMultiplier(s) : 1;
if (multiplier != 1) {
s = s.substring(0, s.length()-1).trim();
Long l = Long.valueOf(s) * multiplier;
if (tc == Integer.TYPE)
return (T)Integer.valueOf(l.intValue());
if (tc == Short.TYPE)
return (T)Short.valueOf(l.shortValue());
if (tc == Long.TYPE)
return (T)Long.valueOf(l.longValue());
} else {
if (tc == Integer.TYPE)
return (T)Integer.valueOf(s);
if (tc == Short.TYPE)
return (T)Short.valueOf(s);
if (tc == Long.TYPE)
return (T)Long.valueOf(s);
if (tc == Float.TYPE)
return (T)new Float(s);
if (tc == Double.TYPE)
return (T)new Double(s);
if (tc == Byte.TYPE)
return (T)Byte.valueOf(s);
}
}
} else if (to.isChar()) {
if (isNullOrEmpty(value))
return (T)to.info.getPrimitiveDefault();
return (T)parseCharacter(value);
} else if (to.isBoolean()) {
if (from.isNumber()) {
int i = ((Number)value).intValue();
return (T)(i == 0 ? Boolean.FALSE : Boolean.TRUE);
} else if (isNullOrEmpty(value)) {
return (T)to.info.getPrimitiveDefault();
} else {
return (T)Boolean.valueOf(value.toString());
}
}
}
if (to.isNumber()) {
if (from.isNumber()) {
Number n = (Number)value;
if (tc == Integer.class)
return (T)Integer.valueOf(n.intValue());
if (tc == Short.class)
return (T)Short.valueOf(n.shortValue());
if (tc == Long.class)
return (T)Long.valueOf(n.longValue());
if (tc == Float.class)
return (T)Float.valueOf(n.floatValue());
if (tc == Double.class)
return (T)Double.valueOf(n.doubleValue());
if (tc == Byte.class)
return (T)Byte.valueOf(n.byteValue());
if (tc == AtomicInteger.class)
return (T)new AtomicInteger(n.intValue());
if (tc == AtomicLong.class)
return (T)new AtomicLong(n.intValue());
} else if (from.isBoolean()) {
Boolean b = (Boolean)value;
if (tc == Integer.class)
return (T)Integer.valueOf(b ? 1 : 0);
if (tc == Short.class)
return (T)Short.valueOf(b ? (short)1 : 0);
if (tc == Long.class)
return (T)Long.valueOf(b ? 1 : 0);
if (tc == Float.class)
return (T)Float.valueOf(b ? 1 : 0);
if (tc == Double.class)
return (T)Double.valueOf(b ? 1 : 0);
if (tc == Byte.class)
return (T)Byte.valueOf(b ? (byte)1 : 0);
if (tc == AtomicInteger.class)
return (T)new AtomicInteger(b ? 1 : 0);
if (tc == AtomicLong.class)
return (T)new AtomicLong(b ? 1 : 0);
} else if (isNullOrEmpty(value)) {
return null;
} else if (! hasMutater(from, to)) {
String s = value.toString();
int multiplier = (tc == Integer.class || tc == Short.class || tc == Long.class) ? getMultiplier(s) : 1;
if (multiplier != 1) {
s = s.substring(0, s.length()-1).trim();
Long l = Long.valueOf(s) * multiplier;
if (tc == Integer.TYPE)
return (T)Integer.valueOf(l.intValue());
if (tc == Short.TYPE)
return (T)Short.valueOf(l.shortValue());
if (tc == Long.TYPE)
return (T)Long.valueOf(l.longValue());
} else {
if (tc == Integer.class)
return (T)Integer.valueOf(s);
if (tc == Short.class)
return (T)Short.valueOf(s);
if (tc == Long.class)
return (T)Long.valueOf(s);
if (tc == Float.class)
return (T)new Float(s);
if (tc == Double.class)
return (T)new Double(s);
if (tc == Byte.class)
return (T)Byte.valueOf(s);
if (tc == AtomicInteger.class)
return (T)new AtomicInteger(Integer.valueOf(s));
if (tc == AtomicLong.class)
return (T)new AtomicLong(Long.valueOf(s));
if (tc == Number.class)
return (T)StringUtils.parseNumber(s, Number.class);
}
}
}
if (to.isChar()) {
if (isNullOrEmpty(value))
return null;
String s = value.toString();
if (s.length() == 1)
return (T)Character.valueOf(s.charAt(0));
}
if (to.isByteArray()) {
if (from.isInputStream())
return (T)IOUtils.readBytes((InputStream)value, 1024);
if (from.isReader())
return (T)IOUtils.read((Reader)value).getBytes();
}
// Handle setting of array properties
if (to.isArray()) {
if (from.isCollection())
return (T)toArray(to, (Collection)value);
else if (from.isArray())
return (T)toArray(to, Arrays.asList((Object[])value));
else if (startsWith(value.toString(), '['))
return (T)toArray(to, new ObjectList(value.toString()).setBeanSession(this));
else if (to.hasMutaterFrom(from))
return to.mutateFrom(value);
else if (from.hasMutaterTo(to))
return from.mutateTo(value, to);
else
return (T)toArray(to, new ObjectList((Object[])StringUtils.split(value.toString())).setBeanSession(this));
}
// Target type is some sort of Map that needs to be converted.
if (to.isMap()) {
try {
if (from.isMap()) {
Map m = to.canCreateNewInstance(outer) ? (Map)to.newInstance(outer) : new ObjectMap(this);
ClassMeta keyType = to.getKeyType(), valueType = to.getValueType();
for (Map.Entry e : (Set<Map.Entry>)((Map)value).entrySet()) {
Object k = e.getKey();
if (keyType.isNotObject()) {
if (keyType.isString() && k.getClass() != Class.class)
k = k.toString();
else
k = convertToMemberType(m, k, keyType);
}
Object v = e.getValue();
if (valueType.isNotObject())
v = convertToMemberType(m, v, valueType);
m.put(k, v);
}
return (T)m;
} else if (!to.canCreateNewInstanceFromString(outer)) {
ObjectMap m = new ObjectMap(value.toString());
m.setBeanSession(this);
return convertToMemberType(outer, m, to);
}
} catch (Exception e) {
throw new InvalidDataConversionException(value.getClass(), to, e);
}
}
// Target type is some sort of Collection
if (to.isCollection()) {
try {
Collection l = to.canCreateNewInstance(outer) ? (Collection)to.newInstance(outer) : to.isSet() ? new LinkedHashSet<>() : new ObjectList(this);
ClassMeta elementType = to.getElementType();
if (from.isArray())
for (Object o : (Object[])value)
l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
else if (from.isCollection())
for (Object o : (Collection)value)
l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
else if (from.isMap())
l.add(elementType.isObject() ? value : convertToMemberType(l, value, elementType));
else if (isNullOrEmpty(value))
return null;
else if (from.isString()) {
String s = value.toString();
if (isObjectList(s, false)) {
ObjectList l2 = new ObjectList(s);
l2.setBeanSession(this);
for (Object o : l2)
l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
} else {
throw new InvalidDataConversionException(value.getClass(), to, null);
}
}
else
throw new InvalidDataConversionException(value.getClass(), to, null);
return (T)l;
} catch (InvalidDataConversionException e) {
throw e;
} catch (Exception e) {
throw new InvalidDataConversionException(value.getClass(), to, e);
}
}
if (to.isEnum()) {
if (to.canCreateNewInstanceFromString(outer))
return to.newInstanceFromString(outer, value.toString());
if (isNullOrEmpty(value))
return null;
return (T)Enum.valueOf((Class<? extends Enum>)tc, value.toString());
}
if (to.isString()) {
if (from.isByteArray()) {
return (T) new String((byte[])value);
} else if (from.isMapOrBean() || from.isCollectionOrArrayOrOptional()) {
if (SimpleJsonSerializer.DEFAULT != null)
return (T)SimpleJsonSerializer.DEFAULT.serialize(value);
} else if (from.isClass()) {
return (T)((Class<?>)value).getName();
}
return (T)value.toString();
}
if (to.isCharSequence()) {
Class<?> c = value.getClass();
if (c.isArray()) {
if (c.getComponentType().isPrimitive()) {
ObjectList l = new ObjectList(this);
int size = Array.getLength(value);
for (int i = 0; i < size; i++)
l.add(Array.get(value, i));
value = l;
}
value = new ObjectList((Object[])value).setBeanSession(this);
}
return to.newInstanceFromString(outer, value.toString());
}
if (to.isBoolean()) {
if (from.isNumber())
return (T)(Boolean.valueOf(((Number)value).intValue() != 0));
if (isNullOrEmpty(value))
return null;
if (! hasMutater(from, to))
return (T)Boolean.valueOf(value.toString());
}
// It's a bean being initialized with a Map
if (to.isBean() && value instanceof Map) {
BuilderSwap<T,Object> builder = (BuilderSwap<T,Object>)to.getBuilderSwap(this);
if (value instanceof ObjectMap && builder == null) {
ObjectMap m2 = (ObjectMap)value;
String typeName = m2.getString(getBeanTypePropertyName(to));
if (typeName != null) {
ClassMeta cm = to.getBeanRegistry().getClassMeta(typeName);
if (cm != null && to.info.isParentOf(cm.innerClass))
return (T)m2.cast(cm);
}
}
if (builder != null) {
BeanMap m = toBeanMap(builder.create(this, to));
m.load((Map<?,?>) value);
return builder.build(this, m.getBean(), to);
}
return newBeanMap(tc).load((Map<?,?>) value).getBean();
}
if (to.isInputStream()) {
if (from.isByteArray()) {
byte[] b = (byte[])value;
return (T) new ByteArrayInputStream(b, 0, b.length);
}
byte[] b = value.toString().getBytes();
return (T)new ByteArrayInputStream(b, 0, b.length);
}
if (to.isReader()) {
if (from.isByteArray()) {
byte[] b = (byte[])value;
return (T) new StringReader(new String(b));
}
return (T)new StringReader(value.toString());
}
if (to.isCalendar()) {
if (from.isCalendar()) {
Calendar c = (Calendar)value;
if (value instanceof GregorianCalendar) {
GregorianCalendar c2 = new GregorianCalendar(c.getTimeZone());
c2.setTime(c.getTime());
return (T)c2;
}
}
if (from.isDate()) {
Date d = (Date)value;
if (value instanceof GregorianCalendar) {
GregorianCalendar c2 = new GregorianCalendar(TimeZone.getDefault());
c2.setTime(d);
return (T)c2;
}
}
}
if (to.isDate() && to.getInnerClass() == Date.class) {
if (from.isCalendar())
return (T)((Calendar)value).getTime();
}
if (to.hasMutaterFrom(from))
return to.mutateFrom(value);
if (from.hasMutaterTo(to))
return from.mutateTo(value, to);
if (to.isBean())
return newBeanMap(to.getInnerClass()).load(value.toString()).getBean();
if (to.canCreateNewInstanceFromString(outer))
return to.newInstanceFromString(outer, value.toString());
} catch (Exception e) {
throw new InvalidDataConversionException(value, to, e);
}
throw new InvalidDataConversionException(value, to, null);
}
private static boolean hasMutater(ClassMeta<?> from, ClassMeta<?> to) {
return to.hasMutaterFrom(from) || from.hasMutaterTo(to);
}
private static final boolean isNullOrEmpty(Object o) {
return o == null || o.toString().equals("") || o.toString().equals("null");
}
private static int getMultiplier(String s) {
if (s.endsWith("G"))
return 1024*1024*1024;
if (s.endsWith("M"))
return 1024*1024;
if (s.endsWith("K"))
return 1024;
return 1;
}
/**
* Converts the contents of the specified list into an array.
*
* <p>
* Works on both object and primitive arrays.
*
* <p>
* In the case of multi-dimensional arrays, the incoming list must contain elements of type n-1 dimension.
* i.e. if {@code type} is <code><jk>int</jk>[][]</code> then {@code list} must have entries of type
* <code><jk>int</jk>[]</code>.
*
* @param type The type to convert to. Must be an array type.
* @param list The contents to populate the array with.
* @return A new object or primitive array.
*/
protected final Object toArray(ClassMeta<?> type, Collection<?> list) {
if (list == null)
return null;
ClassMeta<?> componentType = type.isArgs() ? object() : type.getElementType();
Object array = Array.newInstance(componentType.getInnerClass(), list.size());
int i = 0;
for (Object o : list) {
if (! type.getInnerClass().isInstance(o)) {
if (componentType.isArray() && o instanceof Collection)
o = toArray(componentType, (Collection<?>)o);
else if (o == null && componentType.isPrimitive())
o = componentType.getPrimitiveDefault();
else
o = convertToType(o, componentType);
}
try {
Array.set(array, i++, o);
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw e;
}
}
return array;
}
/**
* Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}).
*
* <p>
* If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
* bean.
*
* <h5 class='section'>Example:</h5>
* <p class='bcode w800'>
* <jc>// Construct a bean map around a bean instance</jc>
* BeanMap&lt;Person&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> Person());
* </p>
*
* @param <T> The class of the object being wrapped.
* @param o The object to wrap in a map interface. Must not be null.
* @return The wrapped object.
*/
public final <T> BeanMap<T> toBeanMap(T o) {
return this.toBeanMap(o, (Class<T>)o.getClass());
}
/**
* Determines whether the specified object matches the requirements on this context of being a bean.
*
* @param o The object being tested.
* @return <jk>true</jk> if the specified object is considered a bean.
*/
public final boolean isBean(Object o) {
if (o == null)
return false;
return isBean(o.getClass());
}
/**
* Determines whether the specified class matches the requirements on this context of being a bean.
*
* @param c The class being tested.
* @return <jk>true</jk> if the specified class is considered a bean.
*/
public final boolean isBean(Class<?> c) {
return getBeanMeta(c) != null;
}
/**
* Wraps an object inside a {@link BeanMap} object (i.e.: a modifiable {@link Map}) defined as a bean for one of its
* class, a super class, or an implemented interface.
*
* <p>
* If object is not a true bean, throws a {@link BeanRuntimeException} with an explanation of why it's not a bean.
*
* <h5 class='section'>Example:</h5>
* <p class='bcode w800'>
* <jc>// Construct a bean map for new bean using only properties defined in a superclass</jc>
* BeanMap&lt;MySubBean&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> MySubBean(), MySuperBean.<jk>class</jk>);
*
* <jc>// Construct a bean map for new bean using only properties defined in an interface</jc>
* BeanMap&lt;MySubBean&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.forBean(<jk>new</jk> MySubBean(), MySuperInterface.<jk>class</jk>);
* </p>
*
* @param <T> The class of the object being wrapped.
* @param o The object to wrap in a bean interface. Must not be null.
* @param c The superclass to narrow the bean properties to. Must not be null.
* @return The bean representation, or <jk>null</jk> if the object is not a true bean.
* @throws NullPointerException If either parameter is null.
* @throws IllegalArgumentException If the specified object is not an an instance of the specified class.
* @throws
* BeanRuntimeException If specified object is not a bean according to the bean rules specified in this context
* class.
*/
public final <T> BeanMap<T> toBeanMap(T o, Class<? super T> c) throws BeanRuntimeException {
assertFieldNotNull(o, "o");
assertFieldNotNull(c, "c");
if (! c.isInstance(o))
illegalArg("The specified object is not an instance of the specified class. class=''{0}'', objectClass=''{1}'', object=''{2}''", c.getName(), o.getClass().getName(), 0);
ClassMeta cm = getClassMeta(c);
BeanMeta m = cm.getBeanMeta();
if (m == null)
throw new BeanRuntimeException(c, "Class is not a bean. Reason=''{0}''", cm.getNotABeanReason());
return new BeanMap<>(this, o, m);
}
/**
* Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized
* property values.
*
* <p>
* If object is not a true bean, then throws a {@link BeanRuntimeException} with an explanation of why it's not a
* bean.
*
* <h5 class='section'>Example:</h5>
* <p class='bcode w800'>
* <jc>// Construct a new bean map wrapped around a new Person object</jc>
* BeanMap&lt;Person&gt; bm = BeanContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>);
* </p>
*
* @param <T> The class of the object being wrapped.
* @param c The name of the class to create a new instance of.
* @return A new instance of the class.
*/
public final <T> BeanMap<T> newBeanMap(Class<T> c) {
return newBeanMap(null, c);
}
/**
* Same as {@link #newBeanMap(Class)}, except used for instantiating inner member classes that must be instantiated
* within another class instance.
*
* @param <T> The class of the object being wrapped.
* @param c The name of the class to create a new instance of.
* @param outer
* If class is a member class, this is the instance of the containing class.
* Should be <jk>null</jk> if not a member class.
* @return A new instance of the class.
*/
public final <T> BeanMap<T> newBeanMap(Object outer, Class<T> c) {
BeanMeta m = getBeanMeta(c);
if (m == null)
return null;
T bean = null;
if (m.constructorArgs.length == 0)
bean = newBean(outer, c);
return new BeanMap<>(this, bean, m);
}
/**
* Creates a new empty bean of the specified type, except used for instantiating inner member classes that must
* be instantiated within another class instance.
*
* <h5 class='section'>Example:</h5>
* <p class='bcode w800'>
* <jc>// Construct a new instance of the specified bean class</jc>
* Person p = BeanContext.<jsf>DEFAULT</jsf>.newBean(Person.<jk>class</jk>);
* </p>
*
* @param <T> The class type of the bean being created.
* @param c The class type of the bean being created.
* @return A new bean object.
* @throws BeanRuntimeException If the specified class is not a valid bean.
*/
public final <T> T newBean(Class<T> c) throws BeanRuntimeException {
return newBean(null, c);
}
/**
* Same as {@link #newBean(Class)}, except used for instantiating inner member classes that must be instantiated
* within another class instance.
*
* @param <T> The class type of the bean being created.
* @param c The class type of the bean being created.
* @param outer
* If class is a member class, this is the instance of the containing class.
* Should be <jk>null</jk> if not a member class.
* @return A new bean object.
* @throws BeanRuntimeException If the specified class is not a valid bean.
*/
public final <T> T newBean(Object outer, Class<T> c) throws BeanRuntimeException {
ClassMeta<T> cm = getClassMeta(c);
BeanMeta m = cm.getBeanMeta();
if (m == null)
return null;
try {
T o = (T)m.newBean(outer);
if (o == null)
throw new BeanRuntimeException(c, "Class does not have a no-arg constructor.");
return o;
} catch (BeanRuntimeException e) {
throw e;
} catch (Exception e) {
throw new BeanRuntimeException(e);
}
}
/**
* Returns the {@link BeanMeta} class for the specified class.
*
* @param <T> The class type to get the meta-data on.
* @param c The class to get the meta-data on.
* @return
* The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class
* is not a bean per the settings on this context.
*/
public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
if (c == null)
return null;
return getClassMeta(c).getBeanMeta();
}
/**
* Returns a {@code ClassMeta} wrapper around a {@link Class} object.
*
* @param <T> The class type being wrapped.
* @param c The class being wrapped.
* @return The class meta object containing information about the class.
*/
public final <T> ClassMeta<T> getClassMeta(Class<T> c) {
return ctx.getClassMeta(c);
}
/**
* Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have
* <c>ClassMeta</c> values that themselves could be collections or maps.
*
* <p>
* <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the
* element type.
*
* <p>
* <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value
* types.
*
* <p>
* The array can be arbitrarily long to indicate arbitrarily complex data structures.
*
* <h5 class='section'>Examples:</h5>
* <ul>
* <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
* <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
* <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
* <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
* strings.
* <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
* A linked-list containing linked-lists of strings.
* <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
* <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
* containing string keys/values.
* <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
* A map containing string keys and values of lists containing beans.
* </ul>
*
* @param type
* The class to resolve.
* <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
* @param args
* The type arguments of the class if it's a collection or map.
* <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
* <br>Ignored if the main type is not a map or collection.
* @return The class meta.
*/
public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
return ctx.getClassMeta(type, args);
}
/**
* Given an array of {@link Type} objects, returns a {@link ClassMeta} representing those arguments.
*
* <p>
* Constructs a new meta on each call.
*
* @param classes The array of classes to get class metas for.
* @return The args {@link ClassMeta} object corresponding to the classes. Never <jk>null</jk>.
*/
protected final ClassMeta<Object[]> getArgsClassMeta(Type[] classes) {
assertFieldNotNull(classes, "classes");
ClassMeta[] cm = new ClassMeta<?>[classes.length];
for (int i = 0; i < classes.length; i++)
cm[i] = getClassMeta(classes[i]);
return new ClassMeta(cm);
}
/**
* Shortcut for calling {@code getClassMeta(o.getClass())}.
*
* @param <T> The class of the object being passed in.
* @param o The class to find the class type for.
* @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>.
*/
public final <T> ClassMeta<T> getClassMetaForObject(T o) {
return (ClassMeta<T>)getClassMetaForObject(o, null);
}
/**
* Shortcut for calling {@code getClassMeta(o.getClass())} but returns a default value if object is <jk>null</jk>.
*
* @param o The class to find the class type for.
* @param def The default {@link ClassMeta} if the object is null.
* @return The ClassMeta object, or the default value if {@code o} is <jk>null</jk>.
*/
protected final ClassMeta<?> getClassMetaForObject(Object o, ClassMeta<?> def) {
if (o == null)
return def;
return getClassMeta(o.getClass());
}
/**
* Returns the type property name as defined by {@link BeanContext#BEAN_beanTypePropertyName}.
*
* @param cm
* The class meta of the type we're trying to resolve the type name for.
* Can be <jk>null</jk>.
* @return The type property name. Never <jk>null</jk>.
*/
public final String getBeanTypePropertyName(ClassMeta cm) {
String s = cm == null ? null : cm.getBeanTypePropertyName();
return s == null ? getBeanTypePropertyName() : s;
}
/**
* Returns the bean registry defined in this bean context defined by {@link BeanContext#BEAN_beanDictionary}.
*
* @return The bean registry defined in this bean context. Never <jk>null</jk>.
*/
protected final BeanRegistry getBeanRegistry() {
return ctx.getBeanRegistry();
}
/**
* Creates a reusable {@link StringBuilder} object from an internal pool.
*
* <p>
* String builders are returned to the pool by calling {@link #returnStringBuilder(StringBuilder)}.
*
* @return A new or previously returned string builder.
*/
protected final StringBuilder getStringBuilder() {
if (sbStack.isEmpty())
return new StringBuilder();
return sbStack.pop();
}
/**
* Returns a {@link StringBuilder} object back into the internal reuse pool.
*
* @param sb The string builder to return to the pool. No-op if <jk>null</jk>.
*/
protected final void returnStringBuilder(StringBuilder sb) {
if (sb == null)
return;
sb.setLength(0);
sbStack.push(sb);
}
/**
* Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>.
*
* <p>
* This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known.
*
* <p>
* This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
* avoid a hashmap lookup.
*
* @return The {@link ClassMeta} object associated with the <c>Object</c> class.
*/
public final ClassMeta<Object> object() {
return ctx.object();
}
/**
* Returns a reusable {@link ClassMeta} representation for the class <c>String</c>.
*
* <p>
* This <c>ClassMeta</c> is often used to represent key types in maps.
*
* <p>
* This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
* avoid a hashmap lookup.
*
* @return The {@link ClassMeta} object associated with the <c>String</c> class.
*/
public final ClassMeta<String> string() {
return ctx.string();
}
/**
* Returns a reusable {@link ClassMeta} representation for the class <c>Class</c>.
*
* <p>
* This <c>ClassMeta</c> is often used to represent key types in maps.
*
* <p>
* This method is identical to calling <code>getClassMeta(Class.<jk>class</jk>)</code> but uses a cached copy to
* avoid a hashmap lookup.
*
* @return The {@link ClassMeta} object associated with the <c>String</c> class.
*/
public final ClassMeta<Class> _class() {
return ctx._class();
}
//-----------------------------------------------------------------------------------------------------------------
// Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* Configuration property: Minimum bean class visibility.
*
* @see BeanContext#BEAN_beanClassVisibility
* @return
* Classes are not considered beans unless they meet the minimum visibility requirements.
*/
protected final Visibility getBeanClassVisibility() {
return ctx.getBeanClassVisibility();
}
/**
* Configuration property: Minimum bean constructor visibility.
*
* @see BeanContext#BEAN_beanConstructorVisibility
* @return
* Only look for constructors with this specified minimum visibility.
*/
protected final Visibility getBeanConstructorVisibility() {
return ctx.getBeanConstructorVisibility();
}
/**
* Configuration property: Bean dictionary.
*
* @see BeanContext#BEAN_beanDictionary
* @return
* The list of classes that make up the bean dictionary in this bean context.
*/
// TODO - Rename to getBeanDictionary()
protected final List<Class<?>> getBeanDictionaryClasses() {
return ctx.getBeanDictionaryClasses();
}
/**
* Configuration property: Minimum bean field visibility.
*
*
* @see BeanContext#BEAN_beanFieldVisibility
* @return
* Only look for bean fields with this specified minimum visibility.
*/
protected final Visibility getBeanFieldVisibility() {
return ctx.getBeanFieldVisibility();
}
/**
* Configuration property: Bean filters.
*
*
* @see BeanContext#BEAN_beanFilters
* @return
* Only look for bean fields with this specified minimum visibility.
*/
protected BeanFilter[] getBeanFilters() {
return ctx.getBeanFilters();
}
/**
* Configuration property: BeanMap.put() returns old property value.
*
* @see BeanContext#BEAN_beanMapPutReturnsOldValue
* @return
* <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values.
* <br>Otherwise, it returns <jk>null</jk>.
*/
protected final boolean isBeanMapPutReturnsOldValue() {
return ctx.isBeanMapPutReturnsOldValue();
}
/**
* Configuration property: Minimum bean method visibility.
*
* @see BeanContext#BEAN_beanMethodVisibility
* @return
* Only look for bean methods with this specified minimum visibility.
*/
protected final Visibility getBeanMethodVisibility() {
return ctx.getBeanMethodVisibility();
}
/**
* Configuration property: Beans require no-arg constructors.
*
* @see BeanContext#BEAN_beansRequireDefaultConstructor
* @return
* <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean.
* <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
*/
protected final boolean isBeansRequireDefaultConstructor() {
return ctx.isBeansRequireDefaultConstructor();
}
/**
* Configuration property: Beans require Serializable interface.
*
* @see BeanContext#BEAN_beansRequireSerializable
* @return
* <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean.
* <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method.
*/
protected final boolean isBeansRequireSerializable() {
return ctx.isBeansRequireSerializable();
}
/**
* Configuration property: Beans require setters for getters.
*
* @see BeanContext#BEAN_beansRequireSettersForGetters
* @return
* <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean.
* <br>Otherwise, they are ignored.
*/
protected final boolean isBeansRequireSettersForGetters() {
return ctx.isBeansRequireSettersForGetters();
}
/**
* Configuration property: Beans require at least one property.
*
* @see BeanContext#BEAN_beansRequireSomeProperties
* @return
* <jk>true</jk> if a Java class must contain at least 1 property to be considered a bean.
* <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method.
*/
protected final boolean isBeansRequireSomeProperties() {
return ctx.isBeansRequireSomeProperties();
}
/**
* Configuration property: Bean type property name.
*
* @see BeanContext#BEAN_beanTypePropertyName
* @return
* The name of the bean property used to store the dictionary name of a bean type so that the parser knows the data type to reconstruct.
*/
protected final String getBeanTypePropertyName() {
return ctx.getBeanTypePropertyName();
}
/**
* Configuration property: Debug mode.
*
* @see BeanContext#BEAN_debug
* @return
* <jk>true</jk> if debug mode is enabled.
*/
protected final boolean isDebug() {
return debug;
}
/**
* Configuration property: POJO examples.
*
* @see BeanContext#BEAN_examples
* @return
* A map of POJO examples keyed by class name.
*/
protected final Map<String,?> getExamples() {
return ctx.getExamples();
}
/**
* Configuration property: Bean property excludes.
*
* @see BeanContext#BEAN_bpx
* @return
* The list of property names to exclude keyed by class name.
*/
protected final Map<String,String[]> getBpx() {
return ctx.getBpx();
}
/**
* Configuration property: Find fluent setters.
*
* <h5 class='section'>Description:</h5>
* <p>
*
* @see BeanContext#BEAN_fluentSetters
* @return
* <jk>true</jk> if fluent setters are detected on beans.
*/
protected final boolean isFluentSetters() {
return ctx.isFluentSetters();
}
/**
* Configuration property: Ignore invocation errors on getters.
*
* @see BeanContext#BEAN_ignoreInvocationExceptionsOnGetters
* @return
* <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored.
*/
protected final boolean isIgnoreInvocationExceptionsOnGetters() {
return ctx.isIgnoreInvocationExceptionsOnGetters();
}
/**
* Configuration property: Ignore invocation errors on setters.
*
* @see BeanContext#BEAN_ignoreInvocationExceptionsOnSetters
* @return
* <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored.
*/
protected final boolean isIgnoreInvocationExceptionsOnSetters() {
return ctx.isIgnoreInvocationExceptionsOnSetters();
}
/**
* Configuration property: Ignore properties without setters.
*
* <br>Otherwise, a {@code RuntimeException} is thrown.
*
* @see BeanContext#BEAN_ignorePropertiesWithoutSetters
* @return
* <jk>true</jk> if trying to set a value on a bean property without a setter is silently ignored.
*/
protected final boolean isIgnorePropertiesWithoutSetters() {
return ctx.isIgnorePropertiesWithoutSetters();
}
/**
* Configuration property: Ignore unknown properties.
*
* @see BeanContext#BEAN_ignoreUnknownBeanProperties
* @return
* <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored.
* <br>Otherwise, a {@code RuntimeException} is thrown.
*/
protected final boolean isIgnoreUnknownBeanProperties() {
return ctx.isIgnoreUnknownBeanProperties();
}
/**
* Configuration property: Ignore unknown properties with null values.
*
* @see BeanContext#BEAN_ignoreUnknownNullBeanProperties
* @return
* <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property is silently ignored.
*/
protected final boolean isIgnoreUnknownNullBeanProperties() {
return ctx.isIgnoreUnknownNullBeanProperties();
}
/**
* Configuration property: Implementation classes.
*
* @see BeanContext#BEAN_implClasses
* @return
* Implementation classes keyed by interface class names.
*/
protected final Map<String,ClassInfo> getImplClasses() {
return ctx.getImplClasses();
}
/**
* Configuration property: Bean property includes.
*
* @see BeanContext#BEAN_bpi
* @return
* Include properties keyed by class name.
*/
protected final Map<String,String[]> getBpi() {
return ctx.getBpi();
}
/**
* Configuration property: Locale.
*
* <p>
* The locale is determined in the following order:
* <ol>
* <li><c>locale</c> parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_locale} entry in parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_locale} setting on bean context.
* <li>Locale returned by {@link Locale#getDefault()}.
* </ol>
*
* @see BeanContext#BEAN_locale
* @return The session locale.
*/
public final Locale getLocale() {
return locale;
}
/**
* Configuration property: Media type.
*
* <p>
* For example, <js>"application/json"</js>.
*
* @see BeanContext#BEAN_mediaType
* @return The media type for this session, or <jk>null</jk> if not specified.
*/
public final MediaType getMediaType() {
return mediaType;
}
/**
* Configuration property: Bean class exclusions.
*
* @see BeanContext#BEAN_notBeanClasses
* @return
* The list of classes that are explicitly not beans.
*/
protected final Class<?>[] getNotBeanClasses() {
return ctx.getNotBeanClasses();
}
/**
* Configuration property: Bean package exclusions.
*
* @see BeanContext#BEAN_notBeanPackages
* @return
* The list of fully-qualified package names to exclude from being classified as beans.
*/
protected final String[] getNotBeanPackagesNames() {
return ctx.getNotBeanPackagesNames();
}
/**
* Configuration property: Bean package exclusions.
*
* @see BeanContext#BEAN_notBeanPackages
* @return
* The list of package name prefixes to exclude from being classified as beans.
*/
protected final String[] getNotBeanPackagesPrefixes() {
return ctx.getNotBeanPackagesPrefixes();
}
/**
* Configuration property: POJO swaps.
*
* @see BeanContext#BEAN_pojoSwaps
* @return
* The list POJO swaps defined.
*/
protected final PojoSwap<?,?>[] getPojoSwaps() {
return ctx.getPojoSwaps();
}
/**
* Configuration property: Bean property namer.
*
* @see BeanContext#BEAN_propertyNamer
* @return
* The interface used to calculate bean property names.
*/
protected final PropertyNamer getPropertyNamer() {
return ctx.getPropertyNamer();
}
/**
* Configuration property: Sort bean properties.
*
* @see BeanContext#BEAN_sortProperties
* @return
* <jk>true</jk> if all bean properties will be serialized and access in alphabetical order.
*/
protected final boolean isSortProperties() {
return ctx.isSortProperties();
}
/**
* Configuration property: Time zone.
*
* <p>
* The timezone is determined in the following order:
* <ol>
* <li><c>timeZone</c> parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_timeZone} entry in parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_timeZone} setting on bean context.
* </ol>
*
* @see BeanContext#BEAN_timeZone
* @return The session timezone, or <jk>null</jk> if timezone not specified.
*/
public final TimeZone getTimeZone() {
return timeZone;
}
/**
* Configuration property: Time zone.
*
* <p>
* The timezone is determined in the following order:
* <ol>
* <li><c>timeZone</c> parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_timeZone} entry in parameter passed in through constructor.
* <li>{@link BeanContext#BEAN_timeZone} setting on bean context.
* </ol>
*
* @see BeanContext#BEAN_timeZone
* @return The session timezone, or the system timezone if not specified. Never <jk>null</jk>.
*/
public final ZoneId getTimeZoneId() {
return timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId();
}
/**
* Configuration property: Use enum names.
*
* @see BeanContext#BEAN_useEnumNames
* @return
* <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}.
*/
protected final boolean isUseEnumNames() {
return ctx.isUseEnumNames();
}
/**
* Configuration property: Use interface proxies.
*
* @see BeanContext#BEAN_useInterfaceProxies
* @return
* <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an
* {@link InvocationHandler} if there is no other way of instantiating them.
*/
protected final boolean isUseInterfaceProxies() {
return ctx.isUseInterfaceProxies();
}
/**
* Configuration property: Use Java Introspector.
*
* @see BeanContext#BEAN_useJavaBeanIntrospector
* @return
* <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection.
*/
protected final boolean isUseJavaBeanIntrospector() {
return ctx.isUseJavaBeanIntrospector();
}
//-----------------------------------------------------------------------------------------------------------------
// Other methods
//-----------------------------------------------------------------------------------------------------------------
/**
* HTTP part schema of object being serialized or parsed.
*
* @return HTTP part schema of object being serialized or parsed, or <jk>null</jk> if not specified.
*/
public final HttpPartSchema getSchema() {
return schema;
}
@Override /* Session */
public void checkForWarnings() {
if (debug)
super.checkForWarnings();
}
@Override /* Session */
public ObjectMap toMap() {
return super.toMap()
.append("Context", ctx.toMap())
.append("BeanSession", new DefaultFilteringObjectMap()
.append("debug", debug)
.append("locale", locale)
.append("mediaType", mediaType)
.append("schema", schema)
.append("timeZone", timeZone)
);
}
}