protected final T convertToMemberType()

in juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java [493:917]


	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(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;

			ObjectSwap swap = to.getSwap(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.getSwap(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)Float.valueOf(s);
							if (tc == Double.TYPE)
								return (T)Double.valueOf(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)Float.valueOf(s);
						if (tc == Double.class)
							return (T)Double.valueOf(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)readBytes((InputStream)value);
				if (from.isReader())
					return (T)read((Reader)value).getBytes();
				if (to.hasMutaterFrom(from))
					return to.mutateFrom(value);
				if (from.hasMutaterTo(to))
					return from.mutateTo(value, to);
				return (T) value.toString().getBytes(Charset.forName("UTF-8"));
			}

			// 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, alist((Object[])value));
				else if (startsWith(value.toString(), '['))
					return (T)toArray(to, JsonList.ofJson(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 JsonList((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) : newGenericMap(to);
						ClassMeta keyType = to.getKeyType(), valueType = to.getValueType();
						((Map<?,?>)value).forEach((k,v) -> {
							Object k2 = k;
							if (keyType.isNotObject()) {
								if (keyType.isString() && k.getClass() != Class.class)
									k2 = k.toString();
								else
									k2 = convertToMemberType(m, k, keyType);
							}
							Object v2 = v;
							if (valueType.isNotObject())
								v2 = convertToMemberType(m, v, valueType);
							m.put(k2, v2);
						});
						return (T)m;
					} else if (!to.canCreateNewInstanceFromString(outer)) {
						JsonMap m = JsonMap.ofJson(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() ? set() : new JsonList(this);
					ClassMeta elementType = to.getElementType();

					if (from.isArray()) {
						for (int i = 0; i < Array.getLength(value); i++) {
							Object o = Array.get(value, i);
							l.add(elementType.isObject() ? o : convertToMemberType(l, o, elementType));
						}
					}
					else if (from.isCollection())
						((Collection)value).forEach(x -> l.add(elementType.isObject() ? x : convertToMemberType(l, x, 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 (isJsonArray(s, false)) {
							JsonList l2 = JsonList.ofJson(s);
							l2.setBeanSession(this);
							l2.forEach(x -> l.add(elementType.isObject() ? x : convertToMemberType(l, x, 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()) {
				return to.newInstanceFromString(outer, value.toString());
			}

			if (to.isString()) {
				if (from.isByteArray()) {
					return (T) new String((byte[])value);
				} else if (from.isMapOrBean() || from.isCollectionOrArrayOrOptional()) {
					WriterSerializer ws = ctx.getBeanToStringSerializer();
					if (ws != null)
						return (T)ws.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()) {
						JsonList l = new JsonList(this);
						int size = Array.getLength(value);
						for (int i = 0; i < size; i++)
							l.add(Array.get(value, i));
						value = l;
					}
					value = new JsonList((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 JsonMap && builder == null) {
					JsonMap m2 = (JsonMap)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;
					}
				}
				return (T)DatatypeConverter.parseDateTime(DateUtils.toValidISO8601DT(value.toString()));
			}

			if (to.isDate() && to.getInnerClass() == Date.class) {
				if (from.isCalendar())
					return (T)((Calendar)value).getTime();
				return (T)DatatypeConverter.parseDateTime(DateUtils.toValidISO8601DT(value.toString())).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);
	}