// Going to have to have some casts /raw types somewhere so doing it here // keeps them all in one place. There might be a neater / better solution // but I couldn't find it
@SuppressWarnings("unchecked") publicstaticfinalEnum<?> coerceToEnum(final ELContext ctx, final Object obj,
@SuppressWarnings("rawtypes") Class type) {
if (ctx != null) { boolean originalIsPropertyResolved = ctx.isPropertyResolved(); try {
Object result = ctx.getELResolver().convertToType(ctx, obj, type); if (ctx.isPropertyResolved()) { return (Enum<?>) result;
}
} finally {
ctx.setPropertyResolved(originalIsPropertyResolved);
}
}
if (obj == null || "".equals(obj)) { returnnull;
} if (type.isAssignableFrom(obj.getClass())) { return (Enum<?>) obj;
}
publicstaticfinal <T> T coerceToType(final ELContext ctx, final Object obj, finalClass<T> type) throws ELException {
if (ctx != null) { boolean originalIsPropertyResolved = ctx.isPropertyResolved(); try {
T result = ctx.getELResolver().convertToType(ctx, obj, type); if (ctx.isPropertyResolved()) { return result;
}
} finally {
ctx.setPropertyResolved(originalIsPropertyResolved);
}
}
if (type == null || Object.class.equals(type) ||
(obj != null && type.isAssignableFrom(obj.getClass()))) {
@SuppressWarnings("unchecked")
T result = (T) obj; return result;
}
if (!COERCE_TO_ZERO) { if (obj == null && !type.isPrimitive() &&
!String.class.isAssignableFrom(type)) { returnnull;
}
}
if (String.class.equals(type)) {
@SuppressWarnings("unchecked")
T result = (T) coerceToString(ctx, obj); return result;
} if (ELArithmetic.isNumberType(type)) {
@SuppressWarnings("unchecked")
T result = (T) coerceToNumber(ctx, obj, type); return result;
} if (Character.class.equals(type) || Character.TYPE == type) {
@SuppressWarnings("unchecked")
T result = (T) coerceToCharacter(ctx, obj); return result;
} if (Boolean.class.equals(type) || Boolean.TYPE == type) {
@SuppressWarnings("unchecked")
T result = (T) coerceToBoolean(ctx, obj, Boolean.TYPE == type); return result;
} if (type.isEnum()) {
@SuppressWarnings("unchecked")
T result = (T) coerceToEnum(ctx, obj, type); return result;
}
// new to spec if (obj == null) { returnnull;
} if (obj instanceof String) {
String str = (String) obj;
PropertyEditor editor = PropertyEditorManager.findEditor(type); if (editor == null) { if (str.isEmpty()) { returnnull;
} thrownew ELException(MessageFactory.get("error.convert", obj,
obj.getClass(), type));
} else { try {
editor.setAsText(str);
@SuppressWarnings("unchecked")
T result = (T) editor.getValue(); return result;
} catch (RuntimeException e) { if (str.isEmpty()) { returnnull;
} thrownew ELException(MessageFactory.get("error.convert",
obj, obj.getClass(), type), e);
}
}
}
// Handle special case because the syntax for the empty set is the same // for an empty map. The parser will always parse {} as an empty set. if (obj instanceof Set && type == Map.class &&
((Set<?>) obj).isEmpty()) {
@SuppressWarnings("unchecked")
T result = (T) Collections.EMPTY_MAP; return result;
}
// Handle arrays if (type.isArray() && obj.getClass().isArray()) {
@SuppressWarnings("unchecked")
T result = (T) coerceToArray(ctx, obj, type); return result;
}
if (obj instanceof LambdaExpression && isFunctionalInterface(type)) {
T result = coerceToFunctionalInterface(ctx, (LambdaExpression) obj, type); return result;
}
privatestatic Object coerceToArray(final ELContext ctx, final Object obj, finalClass<?> type) { // Note: Nested arrays will result in nested calls to this method.
// Note: Calling method has checked the obj is an array.
int size = Array.getLength(obj); // Cast the input object to an array (calling method has checked it is // an array) // Get the target type for the array elements Class<?> componentType = type.getComponentType(); // Create a new array of the correct type
Object result = Array.newInstance(componentType, size); // Coerce each element in turn. for (int i = 0; i < size; i++) {
Array.set(result, i, coerceToType(ctx, Array.get(obj, i), componentType));
}
return result;
}
privatestatic <T> T coerceToFunctionalInterface(final ELContext ctx, final LambdaExpression lambdaExpression, finalClass<T> type) {
Supplier<T> proxy = () -> { // Create a dynamic proxy for the functional interface
@SuppressWarnings("unchecked")
T result = (T) Proxy.newProxyInstance(type.getClassLoader(), newClass[]{type},
(Object obj, Method method, Object[] args) -> { // Functional interfaces have a single, abstract method if (!Modifier.isAbstract(method.getModifiers())) { thrownew ELException(MessageFactory.get("elSupport.coerce.nonAbstract", type, method));
} if (ctx == null) { return lambdaExpression.invoke(args);
} else { return lambdaExpression.invoke(ctx, args);
}
}); return result;
}; if (System.getSecurityManager() != null) { return AccessController.doPrivileged((PrivilegedAction<T>) proxy::get);
} else { return proxy.get();
}
}
boolean foundAbstractMethod = false;
Method[] methods = type.getMethods(); for (Method method : methods) { if (Modifier.isAbstract(method.getModifiers())) { // Abstract methods that override one of the public methods // of Object don't count if (overridesObjectMethod(method)) { continue;
} if (foundAbstractMethod) { // Found more than one returnfalse;
} else {
foundAbstractMethod = true;
}
}
} return foundAbstractMethod;
}
/* *Copiedtojakarta.el.ELContext-keepinsync
*/ privatestaticboolean overridesObjectMethod(Method method) { // There are three methods that can be overridden if ("equals".equals(method.getName())) { if (method.getReturnType().equals(boolean.class)) { if (method.getParameterCount() == 1) { if (method.getParameterTypes()[0].equals(Object.class)) { returntrue;
}
}
}
} elseif ("hashCode".equals(method.getName())) { if (method.getReturnType().equals(int.class)) { if (method.getParameterCount() == 0) { returntrue;
}
}
} elseif ("toString".equals(method.getName())) { if (method.getReturnType().equals(String.class)) { if (method.getParameterCount() == 0) { returntrue;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.