Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
e1080a07
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
e1080a07
编写于
7月 04, 2013
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' into websocket-stomp
上级
8560582c
2a559028
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
1009 addition
and
176 deletion
+1009
-176
build.gradle
build.gradle
+4
-4
spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultDocumentLoader.java
...ingframework/beans/factory/xml/DefaultDocumentLoader.java
+0
-1
spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java
...ngframework/core/convert/support/ByteBufferConverter.java
+114
-0
spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java
...mework/core/convert/support/DefaultConversionService.java
+6
-0
spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java
...mework/core/convert/support/ByteBufferConverterTests.java
+109
-0
spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java
.../springframework/expression/spel/ast/MethodReference.java
+133
-164
spring-expression/src/test/java/org/springframework/expression/spel/CachedMethodExecutorTests.java
...gframework/expression/spel/CachedMethodExecutorTests.java
+18
-4
spring-websocket/src/main/java/org/springframework/web/socket/adapter/ConvertingEncoderDecoderSupport.java
...k/web/socket/adapter/ConvertingEncoderDecoderSupport.java
+247
-0
spring-websocket/src/main/java/org/springframework/web/socket/server/support/JettyRequestUpgradeStrategy.java
...eb/socket/server/support/JettyRequestUpgradeStrategy.java
+3
-3
spring-websocket/src/test/java/org/springframework/web/socket/ContextLoaderTestUtils.java
...rg/springframework/web/socket/ContextLoaderTestUtils.java
+58
-0
spring-websocket/src/test/java/org/springframework/web/socket/adapter/ConvertingEncoderDecoderSupportTests.java
.../socket/adapter/ConvertingEncoderDecoderSupportTests.java
+317
-0
未找到文件。
build.gradle
浏览文件 @
e1080a07
...
...
@@ -485,12 +485,12 @@ project("spring-websocket") {
}
optional
(
"org.glassfish.tyrus:tyrus-websocket-core:1.0"
)
optional
(
"org.glassfish.tyrus:tyrus-container-servlet:1.0"
)
optional
(
"org.eclipse.jetty:jetty-webapp:9.0.
3.v20130506
"
)
{
optional
(
"org.eclipse.jetty:jetty-webapp:9.0.
4.v20130625
"
)
{
exclude
group:
"org.eclipse.jetty.orbit"
,
module:
"javax.servlet"
}
optional
(
"org.eclipse.jetty.websocket:websocket-server:9.0.
3.v20130506
"
)
optional
(
"org.eclipse.jetty.websocket:websocket-client:9.0.
3.v20130506
"
)
optional
(
"com.fasterxml.jackson.core:jackson-databind:2.2.0"
)
//
currently needed for SockJS support
optional
(
"org.eclipse.jetty.websocket:websocket-server:9.0.
4.v20130625
"
)
optional
(
"org.eclipse.jetty.websocket:websocket-client:9.0.
4.v20130625
"
)
optional
(
"com.fasterxml.jackson.core:jackson-databind:2.2.0"
)
//
required for SockJS support currently
optional
(
"reactor:reactor-core:1.0.0.BUILD-SNAPSHOT"
)
// STOMP message processing
optional
(
"reactor:reactor-tcp:1.0.0.BUILD-SNAPSHOT"
)
// STOMP relay to message broker
}
...
...
spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultDocumentLoader.java
浏览文件 @
e1080a07
...
...
@@ -91,7 +91,6 @@ public class DefaultDocumentLoader implements DocumentLoader {
factory
.
setNamespaceAware
(
namespaceAware
);
if
(
validationMode
!=
XmlValidationModeDetector
.
VALIDATION_NONE
)
{
factory
.
setFeature
(
"http://apache.org/xml/features/validation/schema"
,
false
);
factory
.
setValidating
(
true
);
if
(
validationMode
==
XmlValidationModeDetector
.
VALIDATION_XSD
)
{
// Enforce namespace aware for XSD...
...
...
spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java
0 → 100644
浏览文件 @
e1080a07
/*
* Copyright 2002-2013 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.
* 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.springframework.core.convert.support
;
import
java.nio.ByteBuffer
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Set
;
import
org.springframework.core.convert.ConversionService
;
import
org.springframework.core.convert.TypeDescriptor
;
import
org.springframework.core.convert.converter.ConditionalGenericConverter
;
/**
* Converts a {@link ByteBuffer} directly to and from {@code byte[]}s and indirectly to
* any type that the {@link ConversionService} support via {@code byte[]}.
*
* @author Phillip Webb
*/
public
class
ByteBufferConverter
implements
ConditionalGenericConverter
{
private
static
final
TypeDescriptor
BYTE_BUFFER_TYPE
=
TypeDescriptor
.
valueOf
(
ByteBuffer
.
class
);
private
static
final
TypeDescriptor
BYTE_ARRAY_TYPE
=
TypeDescriptor
.
valueOf
(
byte
[].
class
);
private
static
final
Set
<
ConvertiblePair
>
CONVERTIBLE_PAIRS
;
static
{
Set
<
ConvertiblePair
>
convertiblePairs
=
new
HashSet
<
ConvertiblePair
>();
convertiblePairs
.
add
(
new
ConvertiblePair
(
ByteBuffer
.
class
,
Object
.
class
));
convertiblePairs
.
add
(
new
ConvertiblePair
(
Object
.
class
,
ByteBuffer
.
class
));
CONVERTIBLE_PAIRS
=
Collections
.
unmodifiableSet
(
convertiblePairs
);
}
private
ConversionService
conversionService
;
public
ByteBufferConverter
(
ConversionService
conversionService
)
{
this
.
conversionService
=
conversionService
;
}
@Override
public
Set
<
ConvertiblePair
>
getConvertibleTypes
()
{
return
CONVERTIBLE_PAIRS
;
}
@Override
public
boolean
matches
(
TypeDescriptor
sourceType
,
TypeDescriptor
targetType
)
{
if
(
sourceType
.
isAssignableTo
(
BYTE_BUFFER_TYPE
))
{
return
matchesFromByteBuffer
(
targetType
);
}
if
(
targetType
.
isAssignableTo
(
BYTE_BUFFER_TYPE
))
{
return
matchesToByteBuffer
(
sourceType
);
}
return
false
;
}
private
boolean
matchesFromByteBuffer
(
TypeDescriptor
targetType
)
{
return
(
targetType
.
isAssignableTo
(
BYTE_ARRAY_TYPE
)
||
this
.
conversionService
.
canConvert
(
BYTE_ARRAY_TYPE
,
targetType
));
}
private
boolean
matchesToByteBuffer
(
TypeDescriptor
sourceType
)
{
return
(
sourceType
.
isAssignableTo
(
BYTE_ARRAY_TYPE
)
||
this
.
conversionService
.
canConvert
(
sourceType
,
BYTE_ARRAY_TYPE
));
}
@Override
public
Object
convert
(
Object
source
,
TypeDescriptor
sourceType
,
TypeDescriptor
targetType
)
{
if
(
sourceType
.
isAssignableTo
(
BYTE_BUFFER_TYPE
))
{
return
convertFromByteBuffer
((
ByteBuffer
)
source
,
targetType
);
}
if
(
targetType
.
isAssignableTo
(
BYTE_BUFFER_TYPE
))
{
return
convertToByteBuffer
(
source
,
sourceType
);
}
// Should not happen
throw
new
IllegalStateException
(
"Unexpected source/target types"
);
}
private
Object
convertFromByteBuffer
(
ByteBuffer
source
,
TypeDescriptor
targetType
)
{
byte
[]
bytes
=
new
byte
[
source
.
remaining
()];
source
.
get
(
bytes
);
if
(
targetType
.
isAssignableTo
(
BYTE_ARRAY_TYPE
))
{
return
bytes
;
}
return
this
.
conversionService
.
convert
(
bytes
,
BYTE_ARRAY_TYPE
,
targetType
);
}
private
Object
convertToByteBuffer
(
Object
source
,
TypeDescriptor
sourceType
)
{
byte
[]
bytes
=
(
byte
[])
(
source
instanceof
byte
[]
?
source
:
this
.
conversionService
.
convert
(
source
,
sourceType
,
BYTE_ARRAY_TYPE
));
ByteBuffer
byteBuffer
=
ByteBuffer
.
allocate
(
bytes
.
length
);
byteBuffer
.
put
(
bytes
);
byteBuffer
.
rewind
();
return
byteBuffer
;
}
}
spring-core/src/main/java/org/springframework/core/convert/support/DefaultConversionService.java
浏览文件 @
e1080a07
...
...
@@ -53,6 +53,7 @@ public class DefaultConversionService extends GenericConversionService {
public
static
void
addDefaultConverters
(
ConverterRegistry
converterRegistry
)
{
addScalarConverters
(
converterRegistry
);
addCollectionConverters
(
converterRegistry
);
addBinaryConverters
(
converterRegistry
);
addFallbackConverters
(
converterRegistry
);
}
...
...
@@ -109,6 +110,11 @@ public class DefaultConversionService extends GenericConversionService {
converterRegistry
.
addConverter
(
new
ObjectToCollectionConverter
(
conversionService
));
}
private
static
void
addBinaryConverters
(
ConverterRegistry
converterRegistry
)
{
ConversionService
conversionService
=
(
ConversionService
)
converterRegistry
;
converterRegistry
.
addConverter
(
new
ByteBufferConverter
(
conversionService
));
}
private
static
void
addFallbackConverters
(
ConverterRegistry
converterRegistry
)
{
ConversionService
conversionService
=
(
ConversionService
)
converterRegistry
;
converterRegistry
.
addConverter
(
new
ObjectToObjectConverter
());
...
...
spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java
0 → 100644
浏览文件 @
e1080a07
/*
* Copyright 2002-2013 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.
* 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.springframework.core.convert.support
;
import
java.nio.ByteBuffer
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.core.convert.converter.Converter
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* Tests for {@link ByteBufferConverter}.
*
* @author Phillip Webb
*/
public
class
ByteBufferConverterTests
{
private
GenericConversionService
conversionService
;
@Before
public
void
setup
()
{
this
.
conversionService
=
new
GenericConversionService
();
this
.
conversionService
.
addConverter
(
new
ByteBufferConverter
(
conversionService
));
this
.
conversionService
.
addConverter
(
new
ByteArrayToOtherTypeConverter
());
this
.
conversionService
.
addConverter
(
new
OtherTypeToByteArrayConverter
());
}
@Test
public
void
byteArrayToByteBuffer
()
throws
Exception
{
byte
[]
bytes
=
new
byte
[]
{
1
,
2
,
3
};
ByteBuffer
convert
=
this
.
conversionService
.
convert
(
bytes
,
ByteBuffer
.
class
);
assertThat
(
bytes
,
not
(
sameInstance
(
convert
.
array
())));
assertThat
(
bytes
,
equalTo
(
convert
.
array
()));
}
@Test
public
void
byteBufferToByteArray
()
throws
Exception
{
byte
[]
bytes
=
new
byte
[]
{
1
,
2
,
3
};
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
bytes
);
byte
[]
convert
=
this
.
conversionService
.
convert
(
byteBuffer
,
byte
[].
class
);
assertThat
(
bytes
,
not
(
sameInstance
(
convert
)));
assertThat
(
bytes
,
equalTo
(
convert
));
}
@Test
public
void
byteBufferToOtherType
()
throws
Exception
{
byte
[]
bytes
=
new
byte
[]
{
1
,
2
,
3
};
ByteBuffer
byteBuffer
=
ByteBuffer
.
wrap
(
bytes
);
OtherType
convert
=
this
.
conversionService
.
convert
(
byteBuffer
,
OtherType
.
class
);
assertThat
(
bytes
,
not
(
sameInstance
(
convert
.
bytes
)));
assertThat
(
bytes
,
equalTo
(
convert
.
bytes
));
}
@Test
public
void
otherTypeToByteBuffer
()
throws
Exception
{
byte
[]
bytes
=
new
byte
[]
{
1
,
2
,
3
};
OtherType
otherType
=
new
OtherType
(
bytes
);
ByteBuffer
convert
=
this
.
conversionService
.
convert
(
otherType
,
ByteBuffer
.
class
);
assertThat
(
bytes
,
not
(
sameInstance
(
convert
.
array
())));
assertThat
(
bytes
,
equalTo
(
convert
.
array
()));
}
private
static
class
OtherType
{
private
byte
[]
bytes
;
public
OtherType
(
byte
[]
bytes
)
{
this
.
bytes
=
bytes
;
}
}
private
static
class
ByteArrayToOtherTypeConverter
implements
Converter
<
byte
[],
OtherType
>
{
@Override
public
OtherType
convert
(
byte
[]
source
)
{
return
new
OtherType
(
source
);
}
}
private
static
class
OtherTypeToByteArrayConverter
implements
Converter
<
OtherType
,
byte
[]>
{
@Override
public
byte
[]
convert
(
OtherType
source
)
{
return
source
.
bytes
;
}
}
}
spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java
浏览文件 @
e1080a07
...
...
@@ -42,17 +42,18 @@ import org.springframework.expression.spel.SpelMessage;
*/
public
class
MethodReference
extends
SpelNodeImpl
{
private
final
String
name
;
private
final
boolean
nullSafe
;
private
final
String
name
;
private
volatile
CachedMethodExecutor
cachedExecutor
;
public
MethodReference
(
boolean
nullSafe
,
String
methodName
,
int
pos
,
SpelNodeImpl
...
arguments
)
{
public
MethodReference
(
boolean
nullSafe
,
String
methodName
,
int
pos
,
SpelNodeImpl
...
arguments
)
{
super
(
pos
,
arguments
);
this
.
name
=
methodName
;
this
.
nullSafe
=
nullSafe
;
this
.
name
=
methodName
;
}
...
...
@@ -62,114 +63,102 @@ public class MethodReference extends SpelNodeImpl {
@Override
protected
ValueRef
getValueRef
(
ExpressionState
state
)
throws
EvaluationException
{
TypedValue
currentContext
=
state
.
getActiveContextObject
();
Object
[]
arguments
=
new
Object
[
getChildCount
()];
for
(
int
i
=
0
;
i
<
arguments
.
length
;
i
++)
{
// Make the root object the active context again for evaluating the parameter
// expressions
try
{
state
.
pushActiveContextObject
(
state
.
getRootContextObject
());
arguments
[
i
]
=
this
.
children
[
i
].
getValueInternal
(
state
).
getValue
();
}
finally
{
state
.
popActiveContextObject
();
}
Object
[]
arguments
=
getArguments
(
state
);
if
(
state
.
getActiveContextObject
().
getValue
()
==
null
)
{
throwIfNotNullSafe
(
getArgumentTypes
(
arguments
));
return
ValueRef
.
NullValueRef
.
instance
;
}
if
(
currentContext
.
getValue
()
==
null
)
{
if
(
this
.
nullSafe
)
{
return
ValueRef
.
NullValueRef
.
instance
;
}
else
{
throw
new
SpelEvaluationException
(
getStartPosition
(),
SpelMessage
.
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED
,
FormatHelper
.
formatMethodForMessage
(
this
.
name
,
getTypes
(
arguments
)));
}
}
return
new
MethodValueRef
(
state
,
state
.
getEvaluationContext
(),
state
.
getActiveContextObject
().
getValue
(),
arguments
);
return
new
MethodValueRef
(
state
);
}
@Override
public
TypedValue
getValueInternal
(
ExpressionState
state
)
throws
EvaluationException
{
TypedValue
currentContext
=
state
.
getActiveContextObject
();
Object
[]
arguments
=
new
Object
[
getChildCount
()];
for
(
int
i
=
0
;
i
<
arguments
.
length
;
i
++)
{
// Make the root object the active context again for evaluating the parameter
// expressions
try
{
state
.
pushActiveContextObject
(
state
.
getRootContextObject
());
arguments
[
i
]
=
this
.
children
[
i
].
getValueInternal
(
state
).
getValue
();
}
finally
{
state
.
popActiveContextObject
();
}
}
List
<
TypeDescriptor
>
argumentTypes
=
getTypes
(
arguments
);
if
(
currentContext
.
getValue
()
==
null
)
{
if
(
this
.
nullSafe
)
{
return
TypedValue
.
NULL
;
}
else
{
throw
new
SpelEvaluationException
(
getStartPosition
(),
SpelMessage
.
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED
,
FormatHelper
.
formatMethodForMessage
(
this
.
name
,
argumentTypes
));
}
EvaluationContext
evaluationContext
=
state
.
getEvaluationContext
();
Object
value
=
state
.
getActiveContextObject
().
getValue
();
TypeDescriptor
targetType
=
state
.
getActiveContextObject
().
getTypeDescriptor
();
Object
[]
arguments
=
getArguments
(
state
);
return
getValueInternal
(
evaluationContext
,
value
,
arguments
,
targetType
);
}
private
TypedValue
getValueInternal
(
EvaluationContext
evaluationContext
,
Object
value
,
Object
[]
arguments
,
TypeDescriptor
targetType
)
{
List
<
TypeDescriptor
>
argumentTypes
=
getArgumentTypes
(
arguments
);
if
(
value
==
null
)
{
throwIfNotNullSafe
(
argumentTypes
);
return
TypedValue
.
NULL
;
}
MethodExecutor
executorToUse
=
getCachedExecutor
(
argumentTypes
);
MethodExecutor
executorToUse
=
getCachedExecutor
(
targetType
,
argumentTypes
);
if
(
executorToUse
!=
null
)
{
try
{
return
executorToUse
.
execute
(
state
.
getEvaluationContext
(),
state
.
getActiveContextObject
().
getValue
(),
arguments
);
return
executorToUse
.
execute
(
evaluationContext
,
value
,
arguments
);
}
catch
(
AccessException
ae
)
{
// Two reasons this can occur:
// 1. the method invoked actually threw a real exception
// 2. the method invoked was not passed the arguments it expected and has become 'stale'
// 2. the method invoked was not passed the arguments it expected and
// has become 'stale'
// In the first case we should not retry, in the second case we should see
if there is a
// better suited method.
// In the first case we should not retry, in the second case we should see
//
if there is a
better suited method.
// To determine which situation it is, the AccessException will contain a cause.
// If the cause is an InvocationTargetException, a user exception was thrown inside the method.
// To determine the situation, the AccessException will contain a cause.
// If the cause is an InvocationTargetException, a user exception was
// thrown inside the method.
// Otherwise the method could not be invoked.
throwSimpleExceptionIfPossible
(
stat
e
,
ae
);
throwSimpleExceptionIfPossible
(
valu
e
,
ae
);
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
// at this point we know it wasn't a user problem so worth a retry if a
// better candidate can be found
this
.
cachedExecutor
=
null
;
}
}
// either there was no accessor or it no longer existed
executorToUse
=
findAccessorForMethod
(
this
.
name
,
argumentTypes
,
state
);
this
.
cachedExecutor
=
new
CachedMethodExecutor
(
executorToUse
,
argumentTypes
);
executorToUse
=
findAccessorForMethod
(
this
.
name
,
argumentTypes
,
value
,
evaluationContext
);
this
.
cachedExecutor
=
new
CachedMethodExecutor
(
executorToUse
,
targetType
,
argumentTypes
);
try
{
return
executorToUse
.
execute
(
state
.
getEvaluationContext
()
,
state
.
getActiveContextObject
().
getValue
()
,
arguments
);
return
executorToUse
.
execute
(
evaluationContext
,
value
,
arguments
);
}
catch
(
AccessException
ae
)
{
catch
(
AccessException
ex
)
{
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible
(
state
,
ae
);
throw
new
SpelEvaluationException
(
getStartPosition
(),
ae
,
SpelMessage
.
EXCEPTION_DURING_METHOD_INVOCATION
,
this
.
name
,
state
.
getActiveContextObject
().
getValue
().
getClass
().
getName
(),
ae
.
getMessage
());
throwSimpleExceptionIfPossible
(
value
,
ex
);
throw
new
SpelEvaluationException
(
getStartPosition
(),
ex
,
SpelMessage
.
EXCEPTION_DURING_METHOD_INVOCATION
,
this
.
name
,
value
.
getClass
().
getName
(),
ex
.
getMessage
());
}
}
/**
* Decode the AccessException, throwing a lightweight evaluation exception or, if the cause was a RuntimeException,
* throw the RuntimeException directly.
*/
private
void
throwSimpleExceptionIfPossible
(
ExpressionState
state
,
AccessException
ae
)
{
if
(
ae
.
getCause
()
instanceof
InvocationTargetException
)
{
Throwable
rootCause
=
ae
.
getCause
().
getCause
();
if
(
rootCause
instanceof
RuntimeException
)
{
throw
(
RuntimeException
)
rootCause
;
private
void
throwIfNotNullSafe
(
List
<
TypeDescriptor
>
argumentTypes
)
{
if
(!
this
.
nullSafe
)
{
throw
new
SpelEvaluationException
(
getStartPosition
(),
SpelMessage
.
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED
,
FormatHelper
.
formatMethodForMessage
(
this
.
name
,
argumentTypes
));
}
}
private
Object
[]
getArguments
(
ExpressionState
state
)
{
Object
[]
arguments
=
new
Object
[
getChildCount
()];
for
(
int
i
=
0
;
i
<
arguments
.
length
;
i
++)
{
// Make the root object the active context again for evaluating the parameter
// expressions
try
{
state
.
pushActiveContextObject
(
state
.
getRootContextObject
());
arguments
[
i
]
=
this
.
children
[
i
].
getValueInternal
(
state
).
getValue
();
}
finally
{
state
.
popActiveContextObject
();
}
throw
new
ExpressionInvocationTargetException
(
getStartPosition
(),
"A problem occurred when trying to execute method '"
+
this
.
name
+
"' on object of type '"
+
state
.
getActiveContextObject
().
getValue
().
getClass
().
getName
()
+
"'"
,
rootCause
);
}
return
arguments
;
}
private
List
<
TypeDescriptor
>
getTypes
(
Object
...
arguments
)
{
private
List
<
TypeDescriptor
>
get
Argument
Types
(
Object
...
arguments
)
{
List
<
TypeDescriptor
>
descriptors
=
new
ArrayList
<
TypeDescriptor
>(
arguments
.
length
);
for
(
Object
argument
:
arguments
)
{
descriptors
.
add
(
TypeDescriptor
.
forObject
(
argument
));
...
...
@@ -177,37 +166,25 @@ public class MethodReference extends SpelNodeImpl {
return
Collections
.
unmodifiableList
(
descriptors
);
}
@Override
public
String
toStringAST
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
this
.
name
).
append
(
"("
);
for
(
int
i
=
0
;
i
<
getChildCount
();
i
++)
{
if
(
i
>
0
)
{
sb
.
append
(
","
);
}
sb
.
append
(
getChild
(
i
).
toStringAST
());
private
MethodExecutor
getCachedExecutor
(
TypeDescriptor
target
,
List
<
TypeDescriptor
>
argumentTypes
)
{
if
(
this
.
cachedExecutor
!=
null
&&
this
.
cachedExecutor
.
isSuitable
(
target
,
argumentTypes
))
{
return
this
.
cachedExecutor
.
get
();
}
sb
.
append
(
")"
);
return
sb
.
toString
();
}
private
MethodExecutor
findAccessorForMethod
(
String
name
,
List
<
TypeDescriptor
>
argumentTypes
,
ExpressionState
state
)
throws
SpelEvaluationException
{
return
findAccessorForMethod
(
name
,
argumentTypes
,
state
.
getActiveContextObject
().
getValue
(),
state
.
getEvaluationContext
());
this
.
cachedExecutor
=
null
;
return
null
;
}
private
MethodExecutor
findAccessorForMethod
(
String
name
,
List
<
TypeDescriptor
>
argumentTypes
,
Object
contextObject
,
EvaluationContext
eContext
)
throws
SpelEvaluationException
{
List
<
TypeDescriptor
>
argumentTypes
,
Object
contextObject
,
EvaluationContext
evaluationContext
)
throws
SpelEvaluationException
{
List
<
MethodResolver
>
methodResolvers
=
eContext
.
getMethodResolvers
();
List
<
MethodResolver
>
methodResolvers
=
e
valuation
Context
.
getMethodResolvers
();
if
(
methodResolvers
!=
null
)
{
for
(
MethodResolver
methodResolver
:
methodResolvers
)
{
try
{
MethodExecutor
methodExecutor
=
methodResolver
.
resolve
(
eContext
,
contextObject
,
name
,
argumentTypes
);
MethodExecutor
methodExecutor
=
methodResolver
.
resolve
(
evaluationContext
,
contextObject
,
name
,
argumentTypes
);
if
(
methodExecutor
!=
null
)
{
return
methodExecutor
;
}
...
...
@@ -219,84 +196,71 @@ public class MethodReference extends SpelNodeImpl {
}
}
}
throw
new
SpelEvaluationException
(
getStartPosition
(),
SpelMessage
.
METHOD_NOT_FOUND
,
throw
new
SpelEvaluationException
(
getStartPosition
(),
SpelMessage
.
METHOD_NOT_FOUND
,
FormatHelper
.
formatMethodForMessage
(
name
,
argumentTypes
),
FormatHelper
.
formatClassNameForMessage
(
contextObject
instanceof
Class
?
((
Class
<?>)
contextObject
)
:
contextObject
.
getClass
()));
FormatHelper
.
formatClassNameForMessage
(
contextObject
instanceof
Class
?
((
Class
<?>)
contextObject
)
:
contextObject
.
getClass
()));
}
/**
* Decode the AccessException, throwing a lightweight evaluation exception or, if the
* cause was a RuntimeException, throw the RuntimeException directly.
*/
private
void
throwSimpleExceptionIfPossible
(
Object
value
,
AccessException
ae
)
{
if
(
ae
.
getCause
()
instanceof
InvocationTargetException
)
{
Throwable
rootCause
=
ae
.
getCause
().
getCause
();
if
(
rootCause
instanceof
RuntimeException
)
{
throw
(
RuntimeException
)
rootCause
;
}
throw
new
ExpressionInvocationTargetException
(
getStartPosition
(),
"A problem occurred when trying to execute method '"
+
this
.
name
+
"' on object of type '"
+
value
.
getClass
().
getName
()
+
"'"
,
rootCause
);
}
}
private
MethodExecutor
getCachedExecutor
(
List
<
TypeDescriptor
>
argumentTypes
)
{
if
(
this
.
cachedExecutor
==
null
||
!
this
.
cachedExecutor
.
isSuitable
(
argumentTypes
))
{
this
.
cachedExecutor
=
null
;
return
null
;
@Override
public
String
toStringAST
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
this
.
name
).
append
(
"("
);
for
(
int
i
=
0
;
i
<
getChildCount
();
i
++)
{
if
(
i
>
0
)
{
sb
.
append
(
","
);
}
sb
.
append
(
getChild
(
i
).
toStringAST
());
}
return
this
.
cachedExecutor
.
get
();
sb
.
append
(
")"
);
return
sb
.
toString
();
}
private
class
MethodValueRef
implements
ValueRef
{
private
final
ExpressionState
state
;
private
final
EvaluationContext
evaluationContext
;
private
EvaluationContext
evaluationContext
;
private
final
Object
target
;
private
Object
value
;
private
final
Object
[]
arguments
;
private
TypeDescriptor
targetType
;
private
List
<
TypeDescriptor
>
argumentType
s
;
private
Object
[]
argument
s
;
MethodValueRef
(
ExpressionState
state
,
EvaluationContext
evaluationContext
,
Object
object
,
Object
[]
arguments
)
{
this
.
state
=
state
;
this
.
evaluationContext
=
evaluationContext
;
this
.
target
=
object
;
this
.
arguments
=
arguments
;
this
.
argumentTypes
=
getTypes
(
this
.
arguments
);
MethodValueRef
(
ExpressionState
state
)
{
this
.
evaluationContext
=
state
.
getEvaluationContext
();
this
.
value
=
state
.
getActiveContextObject
().
getValue
();
this
.
targetType
=
state
.
getActiveContextObject
().
getTypeDescriptor
();
this
.
arguments
=
getArguments
(
state
);
}
@Override
public
TypedValue
getValue
()
{
MethodExecutor
executorToUse
=
getCachedExecutor
(
this
.
argumentTypes
);
if
(
executorToUse
!=
null
)
{
try
{
return
executorToUse
.
execute
(
this
.
evaluationContext
,
this
.
target
,
this
.
arguments
);
}
catch
(
AccessException
ae
)
{
// Two reasons this can occur:
// 1. the method invoked actually threw a real exception
// 2. the method invoked was not passed the arguments it expected and has become 'stale'
// In the first case we should not retry, in the second case we should see if there is a
// better suited method.
// To determine which situation it is, the AccessException will contain a cause.
// If the cause is an InvocationTargetException, a user exception was thrown inside the method.
// Otherwise the method could not be invoked.
throwSimpleExceptionIfPossible
(
this
.
state
,
ae
);
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
MethodReference
.
this
.
cachedExecutor
=
null
;
}
}
// either there was no accessor or it no longer existed
executorToUse
=
findAccessorForMethod
(
MethodReference
.
this
.
name
,
argumentTypes
,
this
.
target
,
this
.
evaluationContext
);
MethodReference
.
this
.
cachedExecutor
=
new
CachedMethodExecutor
(
executorToUse
,
this
.
argumentTypes
);
try
{
return
executorToUse
.
execute
(
this
.
evaluationContext
,
this
.
target
,
this
.
arguments
);
}
catch
(
AccessException
ex
)
{
// Same unwrapping exception handling as above in above catch block
throwSimpleExceptionIfPossible
(
this
.
state
,
ex
);
throw
new
SpelEvaluationException
(
getStartPosition
(),
ex
,
SpelMessage
.
EXCEPTION_DURING_METHOD_INVOCATION
,
MethodReference
.
this
.
name
,
this
.
state
.
getActiveContextObject
().
getValue
().
getClass
().
getName
(),
ex
.
getMessage
());
}
return
MethodReference
.
this
.
getValueInternal
(
this
.
evaluationContext
,
this
.
value
,
this
.
arguments
,
this
.
targetType
);
}
@Override
...
...
@@ -315,18 +279,23 @@ public class MethodReference extends SpelNodeImpl {
private
final
MethodExecutor
methodExecutor
;
private
final
TypeDescriptor
target
;
private
final
List
<
TypeDescriptor
>
argumentTypes
;
public
CachedMethodExecutor
(
MethodExecutor
methodExecutor
,
public
CachedMethodExecutor
(
MethodExecutor
methodExecutor
,
TypeDescriptor
target
,
List
<
TypeDescriptor
>
argumentTypes
)
{
this
.
methodExecutor
=
methodExecutor
;
this
.
target
=
target
;
this
.
argumentTypes
=
argumentTypes
;
}
public
boolean
isSuitable
(
List
<
TypeDescriptor
>
argumentTypes
)
{
return
(
this
.
methodExecutor
!=
null
&&
this
.
argumentTypes
.
equals
(
argumentTypes
));
public
boolean
isSuitable
(
TypeDescriptor
target
,
List
<
TypeDescriptor
>
argumentTypes
)
{
return
(
this
.
methodExecutor
!=
null
&&
this
.
target
!=
null
&&
this
.
target
.
equals
(
target
)
&&
this
.
argumentTypes
.
equals
(
argumentTypes
));
}
public
MethodExecutor
get
()
{
...
...
spring-expression/src/test/java/org/springframework/expression/spel/CachedMethodExecutorTests.java
浏览文件 @
e1080a07
...
...
@@ -45,8 +45,8 @@ public class CachedMethodExecutorTests {
@Test
public
void
testCachedExecution
()
throws
Exception
{
Expression
expression
=
this
.
parser
.
parseExpression
(
"echo(#
something
)"
);
public
void
testCachedExecution
ForParameters
()
throws
Exception
{
Expression
expression
=
this
.
parser
.
parseExpression
(
"echo(#
var
)"
);
assertMethodExecution
(
expression
,
42
,
"int: 42"
);
assertMethodExecution
(
expression
,
42
,
"int: 42"
);
...
...
@@ -54,18 +54,32 @@ public class CachedMethodExecutorTests {
assertMethodExecution
(
expression
,
42
,
"int: 42"
);
}
@Test
public
void
testCachedExecutionForTarget
()
throws
Exception
{
Expression
expression
=
this
.
parser
.
parseExpression
(
"#var.echo(42)"
);
assertMethodExecution
(
expression
,
new
RootObject
(),
"int: 42"
);
assertMethodExecution
(
expression
,
new
RootObject
(),
"int: 42"
);
assertMethodExecution
(
expression
,
new
BaseObject
(),
"String: 42"
);
assertMethodExecution
(
expression
,
new
RootObject
(),
"int: 42"
);
}
private
void
assertMethodExecution
(
Expression
expression
,
Object
var
,
String
expected
)
{
this
.
context
.
setVariable
(
"
something
"
,
var
);
this
.
context
.
setVariable
(
"
var
"
,
var
);
assertEquals
(
expected
,
expression
.
getValue
(
this
.
context
));
}
public
static
class
Root
Object
{
public
static
class
Base
Object
{
public
String
echo
(
String
value
)
{
return
"String: "
+
value
;
}
}
public
static
class
RootObject
extends
BaseObject
{
public
String
echo
(
int
value
)
{
return
"int: "
+
value
;
}
...
...
spring-websocket/src/main/java/org/springframework/web/socket/adapter/ConvertingEncoderDecoderSupport.java
0 → 100644
浏览文件 @
e1080a07
/*
* Copyright 2002-2013 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.
* 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.springframework.web.socket.adapter
;
import
java.nio.ByteBuffer
;
import
javax.websocket.DecodeException
;
import
javax.websocket.Decoder
;
import
javax.websocket.EncodeException
;
import
javax.websocket.Encoder
;
import
javax.websocket.EndpointConfig
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.config.ConfigurableListableBeanFactory
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.core.GenericTypeResolver
;
import
org.springframework.core.convert.ConversionException
;
import
org.springframework.core.convert.ConversionService
;
import
org.springframework.core.convert.TypeDescriptor
;
import
org.springframework.util.Assert
;
import
org.springframework.web.context.ContextLoader
;
/**
* Base class that can be used to implement a standard {@link javax.websocket.Encoder}
* and/or {@link javax.websocket.Decoder}. It provides encode and decode method
* implementations that delegate to a Spring {@link ConversionService}.
*
* <p>By default, this class looks up a {@link ConversionService} registered in the
* {@link #getApplicationContext() active ApplicationContext} under
* the name {@code 'webSocketConversionService'}. This works fine for both client
* and server endpoints, in a Servlet container environment. If not running in a
* Servlet container, subclasses will need to override the
* {@link #getConversionService()} method to provide an alternative lookup strategy.
*
* <p>Subclasses can extend this class and should also implement one or
* both of {@link javax.websocket.Encoder} and {@link javax.websocket.Decoder}.
* For convenience {@link ConvertingEncoderDecoderSupport.BinaryEncoder},
* {@link ConvertingEncoderDecoderSupport.BinaryDecoder},
* {@link ConvertingEncoderDecoderSupport.TextEncoder} and
* {@link ConvertingEncoderDecoderSupport.TextDecoder} subclasses are provided.
*
* <p>Since JSR-356 only allows Encoder/Decoder to be registered by type, instances
* of this class are therefore managed by the WebSocket runtime, and do not need to
* be registered as Spring Beans. They can, however, by injected with Spring-managed
* dependencies via {@link Autowired @Autowire}.
*
* <p>Converters to convert between the {@link #getType() type} and {@code String} or
* {@code ByteBuffer} should be registered.
*
* @author Phillip Webb
* @since 4.0
*
* @param <T> The type being converted to (for Encoder) or from (for Decoder)
* @param <M> The WebSocket message type ({@link String} or {@link ByteBuffer})
*
* @see ConvertingEncoderDecoderSupport.BinaryEncoder
* @see ConvertingEncoderDecoderSupport.BinaryDecoder
* @see ConvertingEncoderDecoderSupport.TextEncoder
* @see ConvertingEncoderDecoderSupport.TextDecoder
*/
public
abstract
class
ConvertingEncoderDecoderSupport
<
T
,
M
>
{
private
static
final
String
CONVERSION_SERVICE_BEAN_NAME
=
"webSocketConversionService"
;
/**
* @see javax.websocket.Encoder#init(EndpointConfig)
* @see javax.websocket.Decoder#init(EndpointConfig)
*/
public
void
init
(
EndpointConfig
config
)
{
ApplicationContext
applicationContext
=
getApplicationContext
();
if
(
applicationContext
!=
null
&&
applicationContext
instanceof
ConfigurableApplicationContext
)
{
ConfigurableListableBeanFactory
beanFactory
=
((
ConfigurableApplicationContext
)
applicationContext
).
getBeanFactory
();
beanFactory
.
autowireBean
(
this
);
}
}
/**
* @see javax.websocket.Encoder#destroy()
* @see javax.websocket.Decoder#destroy()
*/
public
void
destroy
()
{
}
/**
* Strategy method used to obtain the {@link ConversionService}. By default this
* method expects a bean named {@code 'webSocketConversionService'} in the
* {@link #getApplicationContext() active ApplicationContext}.
* @return the {@link ConversionService} (never null)
*/
protected
ConversionService
getConversionService
()
{
ApplicationContext
applicationContext
=
getApplicationContext
();
Assert
.
state
(
applicationContext
!=
null
,
"Unable to locate the Spring ApplicationContext"
);
try
{
return
applicationContext
.
getBean
(
CONVERSION_SERVICE_BEAN_NAME
,
ConversionService
.
class
);
}
catch
(
BeansException
ex
)
{
throw
new
IllegalStateException
(
"Unable to find ConversionService, please configure a '"
+
CONVERSION_SERVICE_BEAN_NAME
+
"' or override getConversionService()"
,
ex
);
}
}
/**
* Returns the active {@link ApplicationContext}. Be default this method obtains
* the context via {@link ContextLoader#getCurrentWebApplicationContext()}, which
* finds the ApplicationContext loaded via {@link ContextLoader} typically in a
* Servlet container environment. When not running in a Servlet container and
* not using {@link ContextLoader}, this method should be overridden.
* @return the {@link ApplicationContext} or {@code null}
*/
protected
ApplicationContext
getApplicationContext
()
{
return
ContextLoader
.
getCurrentWebApplicationContext
();
}
/**
* Returns the type being converted. By default the type is resolved using
* the generic arguments of the class.
*/
protected
TypeDescriptor
getType
()
{
return
TypeDescriptor
.
valueOf
(
resolveTypeArguments
()[
0
]);
}
/**
* Returns the websocket message type. By default the type is resolved using
* the generic arguments of the class.
*/
protected
TypeDescriptor
getMessageType
()
{
return
TypeDescriptor
.
valueOf
(
resolveTypeArguments
()[
1
]);
}
private
Class
<?>[]
resolveTypeArguments
()
{
return
GenericTypeResolver
.
resolveTypeArguments
(
getClass
(),
ConvertingEncoderDecoderSupport
.
class
);
}
/**
* @see javax.websocket.Encoder.Text#encode(Object)
* @see javax.websocket.Encoder.Binary#encode(Object)
*/
@SuppressWarnings
(
"unchecked"
)
public
M
encode
(
T
object
)
throws
EncodeException
{
try
{
return
(
M
)
getConversionService
().
convert
(
object
,
getType
(),
getMessageType
());
}
catch
(
ConversionException
ex
)
{
throw
new
EncodeException
(
object
,
"Unable to encode websocket message using ConversionService"
,
ex
);
}
}
/**
* @see javax.websocket.Decoder.Text#willDecode(String)
* @see javax.websocket.Decoder.Binary#willDecode(ByteBuffer)
*/
public
boolean
willDecode
(
M
bytes
)
{
return
getConversionService
().
canConvert
(
getType
(),
getMessageType
());
}
/**
* @see javax.websocket.Decoder.Text#decode(String)
* @see javax.websocket.Decoder.Binary#decode(ByteBuffer)
*/
@SuppressWarnings
(
"unchecked"
)
public
T
decode
(
M
message
)
throws
DecodeException
{
try
{
return
(
T
)
getConversionService
().
convert
(
message
,
getMessageType
(),
getType
());
}
catch
(
ConversionException
ex
)
{
if
(
message
instanceof
String
)
{
throw
new
DecodeException
((
String
)
message
,
"Unable to decode "
+
"websocket message using ConversionService"
,
ex
);
}
if
(
message
instanceof
ByteBuffer
)
{
throw
new
DecodeException
((
ByteBuffer
)
message
,
"Unable to decode "
+
"websocket message using ConversionService"
,
ex
);
}
throw
ex
;
}
}
/**
* A Binary {@link javax.websocket.Encoder.Binary javax.websocket.Encoder} that
* delegates to Spring's conversion service. See
* {@link ConvertingEncoderDecoderSupport} for details.
*
* @param <T> The type that this Encoder can convert to.
*/
public
static
abstract
class
BinaryEncoder
<
T
>
extends
ConvertingEncoderDecoderSupport
<
T
,
ByteBuffer
>
implements
Encoder
.
Binary
<
T
>
{
}
/**
* A Binary {@link javax.websocket.Encoder.Binary javax.websocket.Encoder} that delegates
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for
* details.
*
* @param <T> The type that this Decoder can convert from.
*/
public
static
abstract
class
BinaryDecoder
<
T
>
extends
ConvertingEncoderDecoderSupport
<
T
,
ByteBuffer
>
implements
Decoder
.
Binary
<
T
>
{
}
/**
* A Text {@link javax.websocket.Encoder.Text javax.websocket.Encoder} that delegates
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for
* details.
*
* @param <T> The type that this Encoder can convert to.
*/
public
static
abstract
class
TextEncoder
<
T
>
extends
ConvertingEncoderDecoderSupport
<
T
,
String
>
implements
Encoder
.
Text
<
T
>
{
}
/**
* A Text {@link javax.websocket.Encoder.Text javax.websocket.Encoder} that delegates
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for
* details.
*
* @param <T> The type that this Decoder can convert from.
*/
public
static
abstract
class
TextDecoder
<
T
>
extends
ConvertingEncoderDecoderSupport
<
T
,
String
>
implements
Decoder
.
Text
<
T
>
{
}
}
spring-websocket/src/main/java/org/springframework/web/socket/server/support/JettyRequestUpgradeStrategy.java
浏览文件 @
e1080a07
...
...
@@ -24,8 +24,8 @@ import javax.servlet.http.HttpServletResponse;
import
org.eclipse.jetty.websocket.api.UpgradeRequest
;
import
org.eclipse.jetty.websocket.api.UpgradeResponse
;
import
org.eclipse.jetty.websocket.server.HandshakeRFC6455
;
import
org.eclipse.jetty.websocket.server.ServletWebSocketRequest
;
import
org.eclipse.jetty.websocket.server.WebSocketServerFactory
;
import
org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest
;
import
org.eclipse.jetty.websocket.servlet.WebSocketCreator
;
import
org.springframework.http.server.ServerHttpRequest
;
import
org.springframework.http.server.ServerHttpResponse
;
...
...
@@ -67,8 +67,8 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
this
.
factory
.
setCreator
(
new
WebSocketCreator
()
{
@Override
public
Object
createWebSocket
(
UpgradeRequest
request
,
UpgradeResponse
response
)
{
Assert
.
isInstanceOf
(
Servlet
WebSocket
Request
.
class
,
request
);
return
((
Servlet
WebSocket
Request
)
request
).
getServletAttributes
().
get
(
WEBSOCKET_LISTENER_ATTR_NAME
);
Assert
.
isInstanceOf
(
Servlet
Upgrade
Request
.
class
,
request
);
return
((
Servlet
Upgrade
Request
)
request
).
getServletAttributes
().
get
(
WEBSOCKET_LISTENER_ATTR_NAME
);
}
});
try
{
...
...
spring-websocket/src/test/java/org/springframework/web/socket/ContextLoaderTestUtils.java
0 → 100644
浏览文件 @
e1080a07
/*
* Copyright 2002-2013 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.
* 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.springframework.web.socket
;
import
java.lang.reflect.Field
;
import
java.util.Map
;
import
org.springframework.web.context.ContextLoader
;
import
org.springframework.web.context.WebApplicationContext
;
/**
* General test utilities for manipulating the {@link ContextLoader}.
*
* @author Phillip Webb
*/
public
class
ContextLoaderTestUtils
{
private
static
Map
<
ClassLoader
,
WebApplicationContext
>
currentContextPerThread
=
getCurrentContextPerThreadFromContextLoader
();
public
static
void
setCurrentWebApplicationContext
(
WebApplicationContext
applicationContext
)
{
setCurrentWebApplicationContext
(
Thread
.
currentThread
().
getContextClassLoader
(),
applicationContext
);
}
public
static
void
setCurrentWebApplicationContext
(
ClassLoader
classLoader
,
WebApplicationContext
applicationContext
)
{
if
(
applicationContext
!=
null
)
{
currentContextPerThread
.
put
(
classLoader
,
applicationContext
);
}
else
{
currentContextPerThread
.
remove
(
classLoader
);
}
}
@SuppressWarnings
(
"unchecked"
)
private
static
Map
<
ClassLoader
,
WebApplicationContext
>
getCurrentContextPerThreadFromContextLoader
()
{
try
{
Field
field
=
ContextLoader
.
class
.
getDeclaredField
(
"currentContextPerThread"
);
field
.
setAccessible
(
true
);
return
(
Map
<
ClassLoader
,
WebApplicationContext
>)
field
.
get
(
null
);
}
catch
(
Exception
ex
)
{
throw
new
IllegalStateException
(
ex
);
}
}
}
spring-websocket/src/test/java/org/springframework/web/socket/adapter/ConvertingEncoderDecoderSupportTests.java
0 → 100644
浏览文件 @
e1080a07
/*
* Copyright 2002-2013 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.
* 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.springframework.web.socket.adapter
;
import
java.nio.ByteBuffer
;
import
javax.websocket.DecodeException
;
import
javax.websocket.Decoder
;
import
javax.websocket.EncodeException
;
import
javax.websocket.Encoder
;
import
org.junit.After
;
import
org.junit.Before
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.convert.ConversionService
;
import
org.springframework.core.convert.ConverterNotFoundException
;
import
org.springframework.core.convert.converter.Converter
;
import
org.springframework.core.convert.support.ByteBufferConverter
;
import
org.springframework.core.convert.support.GenericConversionService
;
import
org.springframework.web.context.WebApplicationContext
;
import
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
;
import
org.springframework.web.socket.ContextLoaderTestUtils
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* Test for {@link ConvertingEncoderDecoderSupport}.
*
* @author Phillip Webb
*/
public
class
ConvertingEncoderDecoderSupportTests
{
private
static
final
String
CONVERTED_TEXT
=
"_test"
;
private
static
final
ByteBuffer
CONVERTED_BYTES
=
ByteBuffer
.
wrap
(
"~test"
.
getBytes
());
@Rule
public
ExpectedException
thown
=
ExpectedException
.
none
();
private
WebApplicationContext
applicationContext
;
private
MyType
myType
=
new
MyType
(
"test"
);
@Before
public
void
setup
()
{
setup
(
Config
.
class
);
}
@After
public
void
teardown
()
{
ContextLoaderTestUtils
.
setCurrentWebApplicationContext
(
null
);
}
private
void
setup
(
Class
<?>
configurationClass
)
{
AnnotationConfigWebApplicationContext
applicationContext
=
new
AnnotationConfigWebApplicationContext
();
applicationContext
.
register
(
configurationClass
);
applicationContext
.
refresh
();
this
.
applicationContext
=
applicationContext
;
ContextLoaderTestUtils
.
setCurrentWebApplicationContext
(
this
.
applicationContext
);
}
@Test
public
void
encodeToText
()
throws
Exception
{
assertThat
(
new
MyTextEncoder
().
encode
(
myType
),
equalTo
(
CONVERTED_TEXT
));
}
@Test
public
void
encodeToTextCannotConvert
()
throws
Exception
{
setup
(
NoConvertersConfig
.
class
);
thown
.
expect
(
EncodeException
.
class
);
thown
.
expectCause
(
isA
(
ConverterNotFoundException
.
class
));
new
MyTextEncoder
().
encode
(
myType
);
}
@Test
public
void
encodeToBinary
()
throws
Exception
{
assertThat
(
new
MyBinaryEncoder
().
encode
(
myType
).
array
(),
equalTo
(
CONVERTED_BYTES
.
array
()));
}
@Test
public
void
encodeToBinaryCannotConvert
()
throws
Exception
{
setup
(
NoConvertersConfig
.
class
);
thown
.
expect
(
EncodeException
.
class
);
thown
.
expectCause
(
isA
(
ConverterNotFoundException
.
class
));
new
MyBinaryEncoder
().
encode
(
myType
);
}
@Test
public
void
decodeFromText
()
throws
Exception
{
Decoder
.
Text
<
MyType
>
decoder
=
new
MyTextDecoder
();
assertThat
(
decoder
.
willDecode
(
CONVERTED_TEXT
),
is
(
true
));
assertThat
(
decoder
.
decode
(
CONVERTED_TEXT
),
equalTo
(
myType
));
}
@Test
public
void
decodeFromTextCannotConvert
()
throws
Exception
{
setup
(
NoConvertersConfig
.
class
);
Decoder
.
Text
<
MyType
>
decoder
=
new
MyTextDecoder
();
assertThat
(
decoder
.
willDecode
(
CONVERTED_TEXT
),
is
(
false
));
thown
.
expect
(
DecodeException
.
class
);
thown
.
expectCause
(
isA
(
ConverterNotFoundException
.
class
));
decoder
.
decode
(
CONVERTED_TEXT
);
}
@Test
public
void
decodeFromBinary
()
throws
Exception
{
Decoder
.
Binary
<
MyType
>
decoder
=
new
MyBinaryDecoder
();
assertThat
(
decoder
.
willDecode
(
CONVERTED_BYTES
),
is
(
true
));
assertThat
(
decoder
.
decode
(
CONVERTED_BYTES
),
equalTo
(
myType
));
}
@Test
public
void
decodeFromBinaryCannotConvert
()
throws
Exception
{
setup
(
NoConvertersConfig
.
class
);
Decoder
.
Binary
<
MyType
>
decoder
=
new
MyBinaryDecoder
();
assertThat
(
decoder
.
willDecode
(
CONVERTED_BYTES
),
is
(
false
));
thown
.
expect
(
DecodeException
.
class
);
thown
.
expectCause
(
isA
(
ConverterNotFoundException
.
class
));
decoder
.
decode
(
CONVERTED_BYTES
);
}
@Test
public
void
encodeAndDecodeText
()
throws
Exception
{
MyTextEncoderDecoder
encoderDecoder
=
new
MyTextEncoderDecoder
();
String
encoded
=
encoderDecoder
.
encode
(
myType
);
assertThat
(
encoderDecoder
.
decode
(
encoded
),
equalTo
(
myType
));
}
@Test
public
void
encodeAndDecodeBytes
()
throws
Exception
{
MyBinaryEncoderDecoder
encoderDecoder
=
new
MyBinaryEncoderDecoder
();
ByteBuffer
encoded
=
encoderDecoder
.
encode
(
myType
);
assertThat
(
encoderDecoder
.
decode
(
encoded
),
equalTo
(
myType
));
}
@Test
public
void
autowiresIntoEncoder
()
throws
Exception
{
WithAutowire
withAutowire
=
new
WithAutowire
();
withAutowire
.
init
(
null
);
assertThat
(
withAutowire
.
config
,
equalTo
(
applicationContext
.
getBean
(
Config
.
class
)));
}
@Test
public
void
cannotFindApplicationContext
()
throws
Exception
{
ContextLoaderTestUtils
.
setCurrentWebApplicationContext
(
null
);
WithAutowire
encoder
=
new
WithAutowire
();
encoder
.
init
(
null
);
thown
.
expect
(
IllegalStateException
.
class
);
thown
.
expectMessage
(
"Unable to locate the Spring ApplicationContext"
);
encoder
.
encode
(
myType
);
}
@Test
public
void
cannotFindConversionService
()
throws
Exception
{
setup
(
NoConfig
.
class
);
MyBinaryEncoder
encoder
=
new
MyBinaryEncoder
();
encoder
.
init
(
null
);
thown
.
expect
(
IllegalStateException
.
class
);
thown
.
expectMessage
(
"Unable to find ConversionService"
);
encoder
.
encode
(
myType
);
}
@Configuration
public
static
class
Config
{
@Bean
public
ConversionService
webSocketConversionService
()
{
GenericConversionService
conversionService
=
new
GenericConversionService
();
conversionService
.
addConverter
(
new
ByteBufferConverter
(
conversionService
));
conversionService
.
addConverter
(
new
MyTypeToStringConverter
());
conversionService
.
addConverter
(
new
MyTypeToBytesConverter
());
conversionService
.
addConverter
(
new
StringToMyTypeConverter
());
conversionService
.
addConverter
(
new
BytesToMyTypeConverter
());
return
conversionService
;
}
}
@Configuration
public
static
class
NoConvertersConfig
{
@Bean
public
ConversionService
webSocketConversionService
()
{
return
new
GenericConversionService
();
}
}
@Configuration
public
static
class
NoConfig
{
}
public
static
class
MyType
{
private
String
value
;
public
MyType
(
String
value
)
{
this
.
value
=
value
;
}
@Override
public
String
toString
()
{
return
this
.
value
;
}
@Override
public
int
hashCode
()
{
return
value
.
hashCode
();
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
MyType
)
{
return
((
MyType
)
obj
).
value
.
equals
(
value
);
}
return
false
;
}
}
private
static
class
MyTypeToStringConverter
implements
Converter
<
MyType
,
String
>
{
@Override
public
String
convert
(
MyType
source
)
{
return
"_"
+
source
.
toString
();
}
}
private
static
class
MyTypeToBytesConverter
implements
Converter
<
MyType
,
byte
[]>
{
@Override
public
byte
[]
convert
(
MyType
source
)
{
return
(
"~"
+
source
.
toString
()).
getBytes
();
}
}
private
static
class
StringToMyTypeConverter
implements
Converter
<
String
,
MyType
>
{
@Override
public
MyType
convert
(
String
source
)
{
return
new
MyType
(
source
.
substring
(
1
));
}
}
private
static
class
BytesToMyTypeConverter
implements
Converter
<
byte
[],
MyType
>
{
@Override
public
MyType
convert
(
byte
[]
source
)
{
return
new
MyType
(
new
String
(
source
).
substring
(
1
));
}
}
public
static
class
MyTextEncoder
extends
ConvertingEncoderDecoderSupport
.
TextEncoder
<
MyType
>
{
}
public
static
class
MyBinaryEncoder
extends
ConvertingEncoderDecoderSupport
.
BinaryEncoder
<
MyType
>
{
}
public
static
class
MyTextDecoder
extends
ConvertingEncoderDecoderSupport
.
TextDecoder
<
MyType
>
{
}
public
static
class
MyBinaryDecoder
extends
ConvertingEncoderDecoderSupport
.
BinaryDecoder
<
MyType
>
{
}
public
static
class
MyTextEncoderDecoder
extends
ConvertingEncoderDecoderSupport
<
MyType
,
String
>
implements
Encoder
.
Text
<
MyType
>,
Decoder
.
Text
<
MyType
>
{
}
public
static
class
MyBinaryEncoderDecoder
extends
ConvertingEncoderDecoderSupport
<
MyType
,
ByteBuffer
>
implements
Encoder
.
Binary
<
MyType
>,
Decoder
.
Binary
<
MyType
>
{
}
public
static
class
WithAutowire
extends
ConvertingEncoderDecoderSupport
.
TextDecoder
<
MyType
>
{
@Autowired
private
Config
config
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录