From bb6d9fabee6442409898cc121217b88f43174db4 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 14 Jul 2017 15:41:38 +0200 Subject: [PATCH] Expression alignment and related polishing (backported from master) --- .../springframework/util/FileSystemUtils.java | 9 +- .../expression/Expression.java | 69 +++--- .../common/CompositeStringExpression.java | 118 ++++++----- .../expression/common/LiteralExpression.java | 101 ++++----- .../spel/standard/SpelExpression.java | 198 ++++++++++-------- .../spel/SpelCompilationCoverageTests.java | 27 +-- .../Jaxb2CollectionHttpMessageConverter.java | 3 +- .../Jaxb2RootElementHttpMessageConverter.java | 5 +- 8 files changed, 273 insertions(+), 257 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java b/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java index 529b4f0178..9776d1eb8a 100644 --- a/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java +++ b/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +58,8 @@ public abstract class FileSystemUtils { * @throws IOException in the case of I/O errors */ public static void copyRecursively(File src, File dest) throws IOException { - Assert.isTrue(src != null && (src.isDirectory() || src.isFile()), "Source File must denote a directory or file"); + Assert.isTrue(src != null && (src.isDirectory() || src.isFile()), + "Source File must denote a directory or file"); Assert.notNull(dest, "Destination File must not be null"); doCopyRecursively(src, dest); } @@ -86,9 +87,7 @@ public abstract class FileSystemUtils { dest.createNewFile(); } catch (IOException ex) { - IOException ioex = new IOException("Failed to create file: " + dest); - ioex.initCause(ex); - throw ioex; + throw new IOException("Failed to create file: " + dest, ex); } FileCopyUtils.copy(src, dest); } diff --git a/spring-expression/src/main/java/org/springframework/expression/Expression.java b/spring-expression/src/main/java/org/springframework/expression/Expression.java index a48c527799..5396bbd83d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/Expression.java +++ b/spring-expression/src/main/java/org/springframework/expression/Expression.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,12 @@ import org.springframework.core.convert.TypeDescriptor; */ public interface Expression { + /** + * Return the original string used to create this expression, unmodified. + * @return the original expression string + */ + String getExpressionString(); + /** * Evaluate this expression in the default standard context. * @return the evaluation result @@ -36,14 +42,6 @@ public interface Expression { */ Object getValue() throws EvaluationException; - /** - * Evaluate this expression against the specified root object - * @param rootObject the root object against which properties/etc will be resolved - * @return the evaluation result - * @throws EvaluationException if there is a problem during evaluation - */ - Object getValue(Object rootObject) throws EvaluationException; - /** * Evaluate the expression in the default context. If the result of the evaluation does not match (and * cannot be converted to) the expected result type then an exception will be returned. @@ -53,6 +51,14 @@ public interface Expression { */ T getValue(Class desiredResultType) throws EvaluationException; + /** + * Evaluate this expression against the specified root object + * @param rootObject the root object against which properties/etc will be resolved + * @return the evaluation result + * @throws EvaluationException if there is a problem during evaluation + */ + Object getValue(Object rootObject) throws EvaluationException; + /** * Evaluate the expression in the default context against the specified root object. If the * result of the evaluation does not match (and cannot be converted to) the expected result type @@ -151,7 +157,7 @@ public interface Expression { TypeDescriptor getValueTypeDescriptor() throws EvaluationException; /** - * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} + * Return the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} * method using the default context. * @param rootObject the root object against which to evaluate the expression * @return a type descriptor for the most general type of value that can be set on this context @@ -160,7 +166,7 @@ public interface Expression { TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException; /** - * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} + * Return the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} * method for the given context. * @param context the context in which to evaluate the expression * @return a type descriptor for the most general type of value that can be set on this context @@ -169,7 +175,7 @@ public interface Expression { TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException; /** - * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} method for + * Return the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} method for * the given context. The supplied root object overrides any specified in the context. * @param context the context in which to evaluate the expression * @param rootObject the root object against which to evaluate the expression @@ -178,6 +184,14 @@ public interface Expression { */ TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException; + /** + * Determine if an expression can be written to, i.e. setValue() can be called. + * @param rootObject the root object against which to evaluate the expression + * @return true if the expression is writable + * @throws EvaluationException if there is a problem determining if it is writable + */ + boolean isWritable(Object rootObject) throws EvaluationException; + /** * Determine if an expression can be written to, i.e. setValue() can be called. * @param context the context in which the expression should be checked @@ -196,23 +210,6 @@ public interface Expression { */ boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException; - /** - * Determine if an expression can be written to, i.e. setValue() can be called. - * @param rootObject the root object against which to evaluate the expression - * @return true if the expression is writable - * @throws EvaluationException if there is a problem determining if it is writable - */ - boolean isWritable(Object rootObject) throws EvaluationException; - - /** - * Set this expression in the provided context to the value provided. - * - * @param context the context in which to set the value of the expression - * @param value the new value - * @throws EvaluationException if there is a problem during evaluation - */ - void setValue(EvaluationContext context, Object value) throws EvaluationException; - /** * Set this expression in the provided context to the value provided. * @param rootObject the root object against which to evaluate the expression @@ -221,6 +218,14 @@ public interface Expression { */ void setValue(Object rootObject, Object value) throws EvaluationException; + /** + * Set this expression in the provided context to the value provided. + * @param context the context in which to set the value of the expression + * @param value the new value + * @throws EvaluationException if there is a problem during evaluation + */ + void setValue(EvaluationContext context, Object value) throws EvaluationException; + /** * Set this expression in the provided context to the value provided. * The supplied root object overrides any specified in the context. @@ -231,10 +236,4 @@ public interface Expression { */ void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException; - /** - * Returns the original string used to create this expression, unmodified. - * @return the original expression string - */ - String getExpressionString(); - } diff --git a/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java b/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java index 7a2abd0398..c9989c8907 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,6 +58,10 @@ public class CompositeStringExpression implements Expression { return this.expressionString; } + public final Expression[] getExpressions() { + return this.expressions; + } + @Override public String getValue() throws EvaluationException { StringBuilder sb = new StringBuilder(); @@ -70,6 +74,12 @@ public class CompositeStringExpression implements Expression { return sb.toString(); } + @Override + public T getValue(Class expectedResultType) throws EvaluationException { + Object value = getValue(); + return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType); + } + @Override public String getValue(Object rootObject) throws EvaluationException { StringBuilder sb = new StringBuilder(); @@ -82,6 +92,12 @@ public class CompositeStringExpression implements Expression { return sb.toString(); } + @Override + public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException { + Object value = getValue(rootObject); + return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType); + } + @Override public String getValue(EvaluationContext context) throws EvaluationException { StringBuilder sb = new StringBuilder(); @@ -94,6 +110,14 @@ public class CompositeStringExpression implements Expression { return sb.toString(); } + @Override + public T getValue(EvaluationContext context, Class expectedResultType) + throws EvaluationException { + + Object value = getValue(context); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); + } + @Override public String getValue(EvaluationContext context, Object rootObject) throws EvaluationException { StringBuilder sb = new StringBuilder(); @@ -107,8 +131,11 @@ public class CompositeStringExpression implements Expression { } @Override - public Class getValueType(EvaluationContext context) { - return String.class; + public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) + throws EvaluationException { + + Object value = getValue(context,rootObject); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType); } @Override @@ -117,53 +144,8 @@ public class CompositeStringExpression implements Expression { } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { - return TypeDescriptor.valueOf(String.class); - } - - @Override - public TypeDescriptor getValueTypeDescriptor() { - return TypeDescriptor.valueOf(String.class); - } - - @Override - public void setValue(EvaluationContext context, Object value) throws EvaluationException { - throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); - } - - @Override - public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { - Object value = getValue(context); - return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); - } - - @Override - public T getValue(Class expectedResultType) throws EvaluationException { - Object value = getValue(); - return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType); - } - - @Override - public boolean isWritable(EvaluationContext context) { - return false; - } - - public Expression[] getExpressions() { - return this.expressions; - } - - - @Override - public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException { - Object value = getValue(rootObject); - return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType); - } - - @Override - public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) - throws EvaluationException { - Object value = getValue(context,rootObject); - return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType); + public Class getValueType(EvaluationContext context) { + return String.class; } @Override @@ -176,24 +158,26 @@ public class CompositeStringExpression implements Expression { return String.class; } + @Override + public TypeDescriptor getValueTypeDescriptor() { + return TypeDescriptor.valueOf(String.class); + } + @Override public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException { return TypeDescriptor.valueOf(String.class); } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException { + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { return TypeDescriptor.valueOf(String.class); } @Override - public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { - return false; - } + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) + throws EvaluationException { - @Override - public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { - throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); + return TypeDescriptor.valueOf(String.class); } @Override @@ -201,9 +185,29 @@ public class CompositeStringExpression implements Expression { return false; } + @Override + public boolean isWritable(EvaluationContext context) { + return false; + } + + @Override + public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { + return false; + } + @Override public void setValue(Object rootObject, Object value) throws EvaluationException { throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); } + @Override + public void setValue(EvaluationContext context, Object value) throws EvaluationException { + throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); + } + + @Override + public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { + throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); + } + } diff --git a/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java b/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java index 1ae6f498d7..65c712e807 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,10 +25,11 @@ import org.springframework.expression.TypedValue; /** * A very simple hardcoded implementation of the Expression interface that represents a * string literal. It is used with CompositeStringExpression when representing a template - * expression which is made up of pieces - some being real expressions to be handled by an - * EL implementation like Spel, and some being just textual elements. + * expression which is made up of pieces - some being real expressions to be handled by + * an EL implementation like SpEL, and some being just textual elements. * * @author Andy Clement + * @author Juergen Hoeller * @since 3.0 */ public class LiteralExpression implements Expression { @@ -47,45 +48,14 @@ public class LiteralExpression implements Expression { return this.literalValue; } - @Override - public String getValue() { - return this.literalValue; - } - - @Override - public String getValue(EvaluationContext context) { - return this.literalValue; - } - - @Override - public String getValue(Object rootObject) { - return this.literalValue; - } - @Override public Class getValueType(EvaluationContext context) { return String.class; } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { - return TypeDescriptor.valueOf(String.class); - } - - @Override - public TypeDescriptor getValueTypeDescriptor() { - return TypeDescriptor.valueOf(String.class); - } - - @Override - public void setValue(EvaluationContext context, Object value) throws EvaluationException { - throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); - } - - @Override - public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { - Object value = getValue(context); - return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); + public String getValue() { + return this.literalValue; } @Override @@ -95,13 +65,8 @@ public class LiteralExpression implements Expression { } @Override - public boolean isWritable(EvaluationContext context) { - return false; - } - - @Override - public Class getValueType() { - return String.class; + public String getValue(Object rootObject) { + return this.literalValue; } @Override @@ -110,17 +75,37 @@ public class LiteralExpression implements Expression { return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType); } + @Override + public String getValue(EvaluationContext context) { + return this.literalValue; + } + + @Override + public T getValue(EvaluationContext context, Class expectedResultType) + throws EvaluationException { + + Object value = getValue(context); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); + } + @Override public String getValue(EvaluationContext context, Object rootObject) throws EvaluationException { return this.literalValue; } @Override - public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException { + public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) + throws EvaluationException { + Object value = getValue(context, rootObject); return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType); } + @Override + public Class getValueType() { + return String.class; + } + @Override public Class getValueType(Object rootObject) throws EvaluationException { return String.class; @@ -131,28 +116,38 @@ public class LiteralExpression implements Expression { return String.class; } + @Override + public TypeDescriptor getValueTypeDescriptor() { + return TypeDescriptor.valueOf(String.class); + } + @Override public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException { return TypeDescriptor.valueOf(String.class); } + @Override + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { + return TypeDescriptor.valueOf(String.class); + } + @Override public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException { return TypeDescriptor.valueOf(String.class); } @Override - public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { + public boolean isWritable(Object rootObject) throws EvaluationException { return false; } @Override - public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { - throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); + public boolean isWritable(EvaluationContext context) { + return false; } @Override - public boolean isWritable(Object rootObject) throws EvaluationException { + public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { return false; } @@ -161,4 +156,14 @@ public class LiteralExpression implements Expression { throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); } + @Override + public void setValue(EvaluationContext context, Object value) throws EvaluationException { + throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); + } + + @Override + public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { + throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); + } + } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java index af4fbd36d6..ff06adfa9b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * references to types, beans, properties, and methods. * * @author Andy Clement + * @author Juergen Hoeller * @since 3.0 */ public class SpelExpression implements Expression { @@ -104,13 +105,20 @@ public class SpelExpression implements Expression { // implementing Expression + @Override + public String getExpressionString() { + return this.expression; + } + @Override public Object getValue() throws EvaluationException { Object result; if (this.compiledAst != null) { try { - TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject(); - return this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext); + TypedValue contextRoot = + (this.evaluationContext != null ? this.evaluationContext.getRootObject() : null); + return this.compiledAst.getValue( + (contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted @@ -130,6 +138,42 @@ public class SpelExpression implements Expression { return result; } + @SuppressWarnings("unchecked") + @Override + public T getValue(Class expectedResultType) throws EvaluationException { + if (this.compiledAst != null) { + try { + TypedValue contextRoot = + (this.evaluationContext != null ? this.evaluationContext.getRootObject() : null); + Object result = this.compiledAst.getValue( + (contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext); + if (expectedResultType == null) { + return (T) result; + } + else { + return ExpressionUtils.convertTypedValue( + getEvaluationContext(), new TypedValue(result), expectedResultType); + } + } + catch (Throwable ex) { + // If running in mixed mode, revert to interpreted + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; + } + else { + // Running in SpelCompilerMode.immediate mode - propagate exception to caller + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + } + } + } + ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration); + TypedValue typedResultValue = this.ast.getTypedValue(expressionState); + checkCompile(expressionState); + return ExpressionUtils.convertTypedValue( + expressionState.getEvaluationContext(), typedResultValue, expectedResultType); + } + @Override public Object getValue(Object rootObject) throws EvaluationException { Object result; @@ -149,44 +193,13 @@ public class SpelExpression implements Expression { } } } - ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration); + ExpressionState expressionState = + new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration); result = this.ast.getValue(expressionState); checkCompile(expressionState); return result; } - @SuppressWarnings("unchecked") - @Override - public T getValue(Class expectedResultType) throws EvaluationException { - if (this.compiledAst != null) { - try { - TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject(); - Object result = this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext); - if (expectedResultType == null) { - return (T)result; - } - else { - return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType); - } - } - catch (Throwable ex) { - // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { - this.interpretedCount = 0; - this.compiledAst = null; - } - else { - // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); - } - } - } - ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration); - TypedValue typedResultValue = this.ast.getTypedValue(expressionState); - checkCompile(expressionState); - return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType); - } - @SuppressWarnings("unchecked") @Override public T getValue(Object rootObject, Class expectedResultType) throws EvaluationException { @@ -197,7 +210,8 @@ public class SpelExpression implements Expression { return (T)result; } else { - return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType); + return ExpressionUtils.convertTypedValue( + getEvaluationContext(), new TypedValue(result), expectedResultType); } } catch (Throwable ex) { @@ -212,10 +226,12 @@ public class SpelExpression implements Expression { } } } - ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration); + ExpressionState expressionState = + new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration); TypedValue typedResultValue = this.ast.getTypedValue(expressionState); checkCompile(expressionState); - return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType); + return ExpressionUtils.convertTypedValue( + expressionState.getEvaluationContext(), typedResultValue, expectedResultType); } @Override @@ -223,8 +239,8 @@ public class SpelExpression implements Expression { Assert.notNull(context, "EvaluationContext is required"); if (compiledAst!= null) { try { - TypedValue contextRoot = context == null ? null : context.getRootObject(); - return this.compiledAst.getValue(contextRoot != null ? contextRoot.getValue() : null, context); + TypedValue contextRoot = context.getRootObject(); + return this.compiledAst.getValue(contextRoot.getValue(), context); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted @@ -244,6 +260,39 @@ public class SpelExpression implements Expression { return result; } + @SuppressWarnings("unchecked") + @Override + public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { + Assert.notNull(context, "EvaluationContext is required"); + if (this.compiledAst != null) { + try { + TypedValue contextRoot = context.getRootObject(); + Object result = this.compiledAst.getValue(contextRoot.getValue(), context); + if (expectedResultType != null) { + return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType); + } + else { + return (T) result; + } + } + catch (Throwable ex) { + // If running in mixed mode, revert to interpreted + if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { + this.interpretedCount = 0; + this.compiledAst = null; + } + else { + // Running in SpelCompilerMode.immediate mode - propagate exception to caller + throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); + } + } + } + ExpressionState expressionState = new ExpressionState(context, this.configuration); + TypedValue typedResultValue = this.ast.getTypedValue(expressionState); + checkCompile(expressionState); + return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType); + } + @Override public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException { Assert.notNull(context, "EvaluationContext is required"); @@ -271,39 +320,9 @@ public class SpelExpression implements Expression { @SuppressWarnings("unchecked") @Override - public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { - if (this.compiledAst != null) { - try { - TypedValue contextRoot = context == null ? null : context.getRootObject(); - Object result = this.compiledAst.getValue(contextRoot==null?null:contextRoot.getValue(),context); - if (expectedResultType != null) { - return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType); - } - else { - return (T) result; - } - } - catch (Throwable ex) { - // If running in mixed mode, revert to interpreted - if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) { - this.interpretedCount = 0; - this.compiledAst = null; - } - else { - // Running in SpelCompilerMode.immediate mode - propagate exception to caller - throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION); - } - } - } - ExpressionState expressionState = new ExpressionState(context, this.configuration); - TypedValue typedResultValue = this.ast.getTypedValue(expressionState); - checkCompile(expressionState); - return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType); - } + public T getValue(EvaluationContext context, Object rootObject, Class expectedResultType) + throws EvaluationException { - @SuppressWarnings("unchecked") - @Override - public T getValue(EvaluationContext context, Object rootObject, Class expectedResultType) throws EvaluationException { if (this.compiledAst != null) { try { Object result = this.compiledAst.getValue(rootObject,context); @@ -377,15 +396,17 @@ public class SpelExpression implements Expression { } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException { + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) + throws EvaluationException { + Assert.notNull(context, "EvaluationContext is required"); ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration); return this.ast.getValueInternal(expressionState).getTypeDescriptor(); } @Override - public String getExpressionString() { - return this.expression; + public boolean isWritable(Object rootObject) throws EvaluationException { + return this.ast.isWritable(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration)); } @Override @@ -394,17 +415,18 @@ public class SpelExpression implements Expression { return this.ast.isWritable(new ExpressionState(context, this.configuration)); } - @Override - public boolean isWritable(Object rootObject) throws EvaluationException { - return this.ast.isWritable(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration)); - } - @Override public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { Assert.notNull(context, "EvaluationContext is required"); return this.ast.isWritable(new ExpressionState(context, toTypedValue(rootObject), this.configuration)); } + @Override + public void setValue(Object rootObject, Object value) throws EvaluationException { + this.ast.setValue( + new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration), value); + } + @Override public void setValue(EvaluationContext context, Object value) throws EvaluationException { Assert.notNull(context, "EvaluationContext is required"); @@ -412,12 +434,9 @@ public class SpelExpression implements Expression { } @Override - public void setValue(Object rootObject, Object value) throws EvaluationException { - this.ast.setValue(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration), value); - } + public void setValue(EvaluationContext context, Object rootObject, Object value) + throws EvaluationException { - @Override - public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { Assert.notNull(context, "EvaluationContext is required"); this.ast.setValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration), value); } @@ -502,12 +521,7 @@ public class SpelExpression implements Expression { } private TypedValue toTypedValue(Object object) { - if (object == null) { - return TypedValue.NULL; - } - else { - return new TypedValue(object); - } + return (object != null ? new TypedValue(object) : TypedValue.NULL); } } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index 4d7efd22ef..efdb7d0294 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java @@ -453,7 +453,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { expression = parser.parseExpression("T(Integer).valueOf(42)"); expression.getValue(Integer.class); assertCanCompile(expression); - assertEquals(new Integer(42), expression.getValue(null, Integer.class)); + assertEquals(new Integer(42), expression.getValue(Integer.class)); // Code gen is different for -1 .. 6 because there are bytecode instructions specifically for those // values @@ -832,9 +832,9 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertEquals("4.0", expression.getValue(ctx).toString()); } - // Confirms visibility of what is being called. @Test public void functionReferenceVisibility_SPR12359() throws Exception { + // Confirms visibility of what is being called. StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod( "compare", Object.class, Object.class)); @@ -845,7 +845,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertCantCompile(expression); // type not public but method is - context = new StandardEvaluationContext(new Object[] {"1"}); + context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod( "compare2", Object.class, Object.class)); context.setVariable("arg", "2"); @@ -856,7 +856,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { @Test public void functionReferenceNonCompilableArguments_SPR12359() throws Exception { - StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {"1"}); + StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("negate", SomeCompareMethod2.class.getDeclaredMethod( "negate", Integer.TYPE)); context.setVariable("arg", "2"); @@ -3072,7 +3072,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, getClass().getClassLoader())); Person3 person = new Person3("foo", 1); SpelExpression expression = parser.parseRaw("#it?.age?.equals([0])"); - StandardEvaluationContext context = new StandardEvaluationContext(new Object[] { 1 }); + StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {1}); context.setVariable("it", person); expression.setEvaluationContext(context); assertTrue(expression.getValue(Boolean.class)); @@ -3099,8 +3099,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { // code generation for ENGLISH should notice there is something on the stack that // is not required and pop it off. expression = parser.parseExpression("#userId.toString().toLowerCase(T(java.util.Locale).ENGLISH)"); - StandardEvaluationContext context = - new StandardEvaluationContext(); + StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("userId", "RoDnEy"); assertEquals("rodney", expression.getValue(context)); assertCanCompile(expression); @@ -3249,8 +3248,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { expression = parser.parseExpression("#it?.age.equals([0])"); Person person = new Person(1); - StandardEvaluationContext context = - new StandardEvaluationContext(new Object[] { person.getAge() }); + StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {person.getAge()}); context.setVariable("it", person); assertTrue(expression.getValue(context, Boolean.class)); assertCanCompile(expression); @@ -3258,26 +3256,23 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { // Variant of above more like what was in the bug report: SpelExpressionParser parser = new SpelExpressionParser( - new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, - getClass().getClassLoader())); + new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, getClass().getClassLoader())); SpelExpression ex = parser.parseRaw("#it?.age.equals([0])"); - context = new StandardEvaluationContext(new Object[] { person.getAge() }); + context = new StandardEvaluationContext(new Object[] {person.getAge()}); context.setVariable("it", person); assertTrue(ex.getValue(context, Boolean.class)); assertTrue(ex.getValue(context, Boolean.class)); PersonInOtherPackage person2 = new PersonInOtherPackage(1); ex = parser.parseRaw("#it?.age.equals([0])"); - context = - new StandardEvaluationContext(new Object[] { person2.getAge() }); + context = new StandardEvaluationContext(new Object[] {person2.getAge()}); context.setVariable("it", person2); assertTrue(ex.getValue(context, Boolean.class)); assertTrue(ex.getValue(context, Boolean.class)); ex = parser.parseRaw("#it?.age.equals([0])"); - context = - new StandardEvaluationContext(new Object[] { person2.getAge() }); + context = new StandardEvaluationContext(new Object[] {person2.getAge()}); context.setVariable("it", person2); assertTrue((Boolean)ex.getValue(context)); assertTrue((Boolean)ex.getValue(context)); diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java index 81f2455a4c..240062ad6b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java @@ -165,7 +165,8 @@ public class Jaxb2CollectionHttpMessageConverter return result; } catch (UnmarshalException ex) { - throw new HttpMessageNotReadableException("Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex); + throw new HttpMessageNotReadableException( + "Could not unmarshal to [" + elementClass + "]: " + ex.getMessage(), ex); } catch (JAXBException ex) { throw new HttpMessageConversionException("Could not instantiate JAXBContext: " + ex.getMessage(), ex); diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java index 5be9e392c9..fe5f780ab0 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -140,8 +140,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa catch (NullPointerException ex) { if (!isSupportDtd()) { throw new HttpMessageNotReadableException("NPE while unmarshalling. " + - "This can happen on JDK 1.6 due to the presence of DTD " + - "declarations, which are disabled.", ex); + "This can happen due to the presence of DTD declarations which are disabled.", ex); } throw ex; }