/* * ============================================================================= * * Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org) * * Licensed 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.thymeleaf.util; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import org.thymeleaf.standard.expression.LiteralValue; /** * * @author Daniel Fernández * * @since 3.0.0 (renamed from org.thymeleaf.util.EvaluationUtil) * */ public final class EvaluationUtils { public static boolean evaluateAsBoolean(final Object condition) { boolean result = true; if (condition == null) { result = false; } else { if (condition instanceof Boolean) { result = ((Boolean)condition).booleanValue(); } else if (condition instanceof Number) { if (condition instanceof BigDecimal) { result = (((BigDecimal) condition).compareTo(BigDecimal.ZERO) != 0); } else if (condition instanceof BigInteger) { result = !condition.equals(BigInteger.ZERO); } else { result = ((Number)condition).doubleValue() != 0.0; } } else if (condition instanceof Character) { result = ((Character) condition).charValue() != 0; } else if (condition instanceof String) { final String condStr = ((String)condition).trim().toLowerCase(); result = !("false".equals(condStr) || "off".equals(condStr) || "no".equals(condStr)); } else if (condition instanceof LiteralValue) { final String condStr = ((LiteralValue)condition).getValue().trim().toLowerCase(); result = !("false".equals(condStr) || "off".equals(condStr) || "no".equals(condStr)); } else { result = true; } } return result; } public static BigDecimal evaluateAsNumber(final Object object) { if (object == null) { return null; } if (object instanceof Number) { if (object instanceof BigDecimal) { return (BigDecimal)object; } else if (object instanceof BigInteger) { return new BigDecimal((BigInteger)object); } else if (object instanceof Byte) { return new BigDecimal(((Byte)object).intValue()); } else if (object instanceof Short) { return new BigDecimal(((Short)object).intValue()); } else if (object instanceof Integer) { return new BigDecimal(((Integer)object).intValue()); } else if (object instanceof Long) { return new BigDecimal(((Long)object).longValue()); } else if (object instanceof Float) { //noinspection UnpredictableBigDecimalConstructorCall return new BigDecimal(((Float)object).doubleValue()); } else if (object instanceof Double) { //noinspection UnpredictableBigDecimalConstructorCall return new BigDecimal(((Double)object).doubleValue()); } } else if (object instanceof String && ((String)object).length() > 0) { final char c0 = ((String)object).charAt(0); // This test will avoid trying to create the BigDecimal most of the times, which // will improve performance by avoiding lots of NumberFormatExceptions if ((c0 >= '0' && c0 <= '9') || c0 == '+' || c0 == '-') { try { return new BigDecimal(((String)object).trim()); } catch (final NumberFormatException ignored) { return null; } } } return null; } public static List<Object> evaluateAsList(final Object value) { // Iterating on null should be the same as iterating an empty list // (for example, <c:forEach>) if (value == null) { return Collections.emptyList(); } final List<Object> result = new ArrayList<Object>(); if (value instanceof Iterable<?>) { for (final Object obj : (Iterable<?>) value) { result.add(obj); } } else if (value instanceof Map<?,?>) { for (final Map.Entry<Object,Object> obj : ((Map<Object,Object>) value).entrySet()) { // We should not directly use the Map.Entry<Object,Object> object used as an iteration // variable because some Map implementations like EnumMap reuse the same Map.Entry in their // iterator()'s, so we would be adding the same object to the list several times. result.add(new MapEntry<Object,Object>(obj.getKey(), obj.getValue())); } } else if (value.getClass().isArray()){ if (value instanceof byte[]) { for (final byte obj : (byte[]) value) { result.add(Byte.valueOf(obj)); } } else if (value instanceof short[]) { for (final short obj : (short[]) value) { result.add(Short.valueOf(obj)); } } else if (value instanceof int[]) { for (final int obj : (int[]) value) { result.add(Integer.valueOf(obj)); } } else if (value instanceof long[]) { for (final long obj : (long[]) value) { result.add(Long.valueOf(obj)); } } else if (value instanceof float[]) { for (final float obj : (float[]) value) { result.add(Float.valueOf(obj)); } } else if (value instanceof double[]) { for (final double obj : (double[]) value) { result.add(Double.valueOf(obj)); } } else if (value instanceof boolean[]) { for (final boolean obj : (boolean[]) value) { result.add(Boolean.valueOf(obj)); } } else if (value instanceof char[]) { for (final char obj : (char[]) value) { result.add(Character.valueOf(obj)); } } else { final Object[] objValue = (Object[]) value; Collections.addAll(result, objValue); } } else{ result.add(value); } return Collections.unmodifiableList(result); } public static Object[] evaluateAsArray(final Object value) { final List<Object> result = new ArrayList<Object>(); if (value == null) { return new Object[] { null }; } if (value instanceof Iterable<?>) { for (final Object obj : (Iterable<?>) value) { result.add(obj); } } else if (value instanceof Map<?,?>) { for (final Object obj : ((Map<?,?>) value).entrySet()) { result.add(obj); } } else if (value.getClass().isArray()){ return (Object[]) value; } else{ result.add(value); } return result.toArray(new Object[result.size()]); } private EvaluationUtils() { super(); } static final class MapEntry<K,V> implements Map.Entry<K,V> { private final K entryKey; private final V entryValue; MapEntry(final K key, final V value) { super(); this.entryKey = key; this.entryValue = value; } public K getKey() { return this.entryKey; } public V getValue() { return this.entryValue; } public V setValue(final V value) { throw new UnsupportedOperationException(); } @Override public String toString() { return this.entryKey + "=" + this.entryValue; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Map.Entry)) { return false; } final Map.Entry mapEntry = (Map.Entry) o; if (this.entryKey != null ? !this.entryKey.equals(mapEntry.getKey()) : mapEntry.getKey() != null) { return false; } if (this.entryValue != null ? !this.entryValue.equals(mapEntry.getValue()) : mapEntry.getValue() != null) { return false; } return true; } @Override public int hashCode() { int result = this.entryKey != null ? this.entryKey.hashCode() : 0; result = 31 * result + (this.entryValue != null ? this.entryValue.hashCode() : 0); return result; } } }