Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
798882bd
Commit
798882bd
authored
Jan 29, 2018
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gh-11584'
parents
6582afea
3a12f98b
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
940 additions
and
171 deletions
+940
-171
EndpointDiscoverer.java
.../boot/actuate/endpoint/annotation/EndpointDiscoverer.java
+10
-21
CacheMetricsRegistrar.java
...ork/boot/actuate/metrics/cache/CacheMetricsRegistrar.java
+10
-39
CacheManagerCustomizers.java
...ork/boot/autoconfigure/cache/CacheManagerCustomizers.java
+5
-30
TransactionManagerCustomizers.java
...oconfigure/transaction/TransactionManagerCustomizers.java
+10
-35
LambdaSafe.java
...c/main/java/org/springframework/boot/util/LambdaSafe.java
+402
-0
package-info.java
...main/java/org/springframework/boot/util/package-info.java
+20
-0
WebServerFactoryCustomizerBeanPostProcessor.java
...b/server/WebServerFactoryCustomizerBeanPostProcessor.java
+8
-46
LambdaSafeTests.java
...t/java/org/springframework/boot/util/LambdaSafeTests.java
+475
-0
No files found.
spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java
View file @
798882bd
...
...
@@ -26,12 +26,10 @@ import java.util.Map;
import
java.util.Objects
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.function.Function
;
import
java.util.function.Supplier
;
import
java.util.stream.Collectors
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.factory.BeanFactoryUtils
;
import
org.springframework.boot.actuate.endpoint.EndpointFilter
;
...
...
@@ -41,6 +39,7 @@ import org.springframework.boot.actuate.endpoint.Operation;
import
org.springframework.boot.actuate.endpoint.invoke.OperationInvoker
;
import
org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor
;
import
org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper
;
import
org.springframework.boot.util.LambdaSafe
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
...
...
@@ -66,8 +65,6 @@ import org.springframework.util.StringUtils;
public
abstract
class
EndpointDiscoverer
<
E
extends
ExposableEndpoint
<
O
>,
O
extends
Operation
>
implements
EndpointsSupplier
<
E
>
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
EndpointDiscoverer
.
class
);
private
final
ApplicationContext
applicationContext
;
private
final
Collection
<
EndpointFilter
<
E
>>
filters
;
...
...
@@ -313,23 +310,15 @@ public abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O exten
return
isFilterMatch
(
filter
,
getFilterEndpoint
(
endpointBean
));
}
@SuppressWarnings
(
"unchecked"
)
private
boolean
isFilterMatch
(
EndpointFilter
<
E
>
filter
,
E
endpoint
)
{
try
{
return
filter
.
match
(
endpoint
);
}
catch
(
ClassCastException
ex
)
{
String
msg
=
ex
.
getMessage
();
if
(
msg
==
null
||
msg
.
startsWith
(
endpoint
.
getClass
().
getName
()))
{
// Possibly a lambda-defined EndpointFilter which we could not resolve the
// generic EndpointInfo type for
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Non-matching Endpoint for EndpointFilter: "
+
filter
,
ex
);
}
return
false
;
}
throw
ex
;
return
LambdaSafe
.
callback
(
EndpointFilter
.
class
,
filter
,
endpoint
)
.
withLogger
(
EndpointDiscoverer
.
class
).
invokeAnd
((
f
)
->
f
.
match
(
endpoint
))
.
get
();
}
public
<
A
,
B
>
void
doIt
(
Function
<
A
,
B
>
x
)
{
}
private
E
getFilterEndpoint
(
EndpointBean
endpointBean
)
{
...
...
spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CacheMetricsRegistrar.java
View file @
798882bd
...
...
@@ -17,16 +17,15 @@
package
org
.
springframework
.
boot
.
actuate
.
metrics
.
cache
;
import
java.util.Collection
;
import
java.util.Objects
;
import
io.micrometer.core.instrument.MeterRegistry
;
import
io.micrometer.core.instrument.Tag
;
import
io.micrometer.core.instrument.Tags
;
import
io.micrometer.core.instrument.binder.MeterBinder
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.boot.util.LambdaSafe
;
import
org.springframework.cache.Cache
;
import
org.springframework.core.ResolvableType
;
/**
* Register supported {@link Cache} to a {@link MeterRegistry}.
...
...
@@ -36,8 +35,6 @@ import org.springframework.core.ResolvableType;
*/
public
class
CacheMetricsRegistrar
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
CacheMetricsRegistrar
.
class
);
private
final
MeterRegistry
registry
;
private
final
String
metricName
;
...
...
@@ -74,41 +71,15 @@ public class CacheMetricsRegistrar {
return
false
;
}
@SuppressWarnings
({
"unchecked"
,
"rawtypes"
})
@SuppressWarnings
({
"unchecked"
})
private
MeterBinder
getMeterBinder
(
Cache
cache
,
Tags
tags
)
{
tags
=
tags
.
and
(
getAdditionalTags
(
cache
));
for
(
CacheMeterBinderProvider
<?>
binderProvider
:
this
.
binderProviders
)
{
Class
<?>
cacheType
=
ResolvableType
.
forClass
(
CacheMeterBinderProvider
.
class
,
binderProvider
.
getClass
())
.
resolveGeneric
();
if
(
cacheType
.
isInstance
(
cache
))
{
try
{
MeterBinder
meterBinder
=
((
CacheMeterBinderProvider
)
binderProvider
)
.
getMeterBinder
(
cache
,
this
.
metricName
,
tags
);
if
(
meterBinder
!=
null
)
{
return
meterBinder
;
}
}
catch
(
ClassCastException
ex
)
{
String
msg
=
ex
.
getMessage
();
if
(
msg
==
null
||
msg
.
startsWith
(
cache
.
getClass
().
getName
()))
{
// Possibly a lambda-defined CacheMeterBinderProvider which we
// could not resolve the generic Cache type for
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Non-matching Cache type for CacheMeterBinderProvider: "
+
binderProvider
,
ex
);
}
}
else
{
throw
ex
;
}
}
}
}
return
null
;
Tags
cacheTags
=
tags
.
and
(
getAdditionalTags
(
cache
));
return
LambdaSafe
.
callbacks
(
CacheMeterBinderProvider
.
class
,
this
.
binderProviders
,
cache
)
.
withLogger
(
CacheMetricsRegistrar
.
class
)
.
invokeAnd
((
binderProvider
)
->
binderProvider
.
getMeterBinder
(
cache
,
this
.
metricName
,
cacheTags
))
.
filter
(
Objects:
:
nonNull
).
findFirst
().
orElse
(
null
);
}
/**
...
...
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheManagerCustomizers.java
View file @
798882bd
...
...
@@ -20,11 +20,8 @@ import java.util.ArrayList;
import
java.util.Collections
;
import
java.util.List
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.boot.util.LambdaSafe
;
import
org.springframework.cache.CacheManager
;
import
org.springframework.core.ResolvableType
;
/**
* Invokes the available {@link CacheManagerCustomizer} instances in the context for a
...
...
@@ -35,8 +32,6 @@ import org.springframework.core.ResolvableType;
*/
public
class
CacheManagerCustomizers
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
CacheManagerCustomizers
.
class
);
private
final
List
<
CacheManagerCustomizer
<?>>
customizers
;
public
CacheManagerCustomizers
(
...
...
@@ -53,32 +48,12 @@ public class CacheManagerCustomizers {
* @param cacheManager the cache manager to customize
* @return the cache manager
*/
@SuppressWarnings
(
"unchecked"
)
public
<
T
extends
CacheManager
>
T
customize
(
T
cacheManager
)
{
for
(
CacheManagerCustomizer
<?>
customizer
:
this
.
customizers
)
{
Class
<?>
generic
=
ResolvableType
.
forClass
(
CacheManagerCustomizer
.
class
,
customizer
.
getClass
())
.
resolveGeneric
();
if
(
generic
.
isInstance
(
cacheManager
))
{
customize
(
cacheManager
,
customizer
);
}
}
LambdaSafe
.
callbacks
(
CacheManagerCustomizer
.
class
,
this
.
customizers
,
cacheManager
)
.
withLogger
(
CacheManagerCustomizers
.
class
)
.
invoke
((
customizer
)
->
customizer
.
customize
(
cacheManager
));
return
cacheManager
;
}
@SuppressWarnings
({
"unchecked"
,
"rawtypes"
})
private
void
customize
(
CacheManager
cacheManager
,
CacheManagerCustomizer
customizer
)
{
try
{
customizer
.
customize
(
cacheManager
);
}
catch
(
ClassCastException
ex
)
{
// Possibly a lambda-defined customizer which we could not resolve the generic
// cache manager type for
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Non-matching cache manager type for customizer: "
+
customizer
,
ex
);
}
}
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizers.java
View file @
798882bd
...
...
@@ -18,12 +18,10 @@ package org.springframework.boot.autoconfigure.transaction;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.List
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.boot.util.LambdaSafe
;
import
org.springframework.transaction.PlatformTransactionManager
;
/**
...
...
@@ -34,44 +32,21 @@ import org.springframework.transaction.PlatformTransactionManager;
*/
public
class
TransactionManagerCustomizers
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
TransactionManagerCustomizers
.
class
);
private
final
List
<
PlatformTransactionManagerCustomizer
<?>>
customizers
;
public
TransactionManagerCustomizers
(
Collection
<?
extends
PlatformTransactionManagerCustomizer
<?>>
customizers
)
{
this
.
customizers
=
(
customizers
==
null
?
null
:
new
ArrayList
<>(
customizers
));
this
.
customizers
=
(
customizers
==
null
?
Collections
.
emptyList
()
:
new
ArrayList
<>(
customizers
));
}
@SuppressWarnings
(
"unchecked"
)
public
void
customize
(
PlatformTransactionManager
transactionManager
)
{
if
(
this
.
customizers
!=
null
)
{
for
(
PlatformTransactionManagerCustomizer
<?>
customizer
:
this
.
customizers
)
{
Class
<?>
generic
=
ResolvableType
.
forClass
(
PlatformTransactionManagerCustomizer
.
class
,
customizer
.
getClass
())
.
resolveGeneric
();
if
(
generic
.
isInstance
(
transactionManager
))
{
customize
(
transactionManager
,
customizer
);
}
}
}
}
@SuppressWarnings
({
"unchecked"
,
"rawtypes"
})
private
void
customize
(
PlatformTransactionManager
transactionManager
,
PlatformTransactionManagerCustomizer
customizer
)
{
try
{
customizer
.
customize
(
transactionManager
);
}
catch
(
ClassCastException
ex
)
{
// Possibly a lambda-defined customizer which we could not resolve the generic
// transaction manager type for
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Non-matching transaction manager type for customizer: "
+
customizer
,
ex
);
}
}
LambdaSafe
.
callbacks
(
PlatformTransactionManagerCustomizer
.
class
,
this
.
customizers
,
transactionManager
)
.
withLogger
(
TransactionManagerCustomizers
.
class
)
.
invoke
((
customizer
)
->
customizer
.
customize
(
transactionManager
));
}
}
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java
0 → 100644
View file @
798882bd
/*
* Copyright 2012-2018 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
.
boot
.
util
;
import
java.util.Collection
;
import
java.util.Optional
;
import
java.util.function.Consumer
;
import
java.util.function.Function
;
import
java.util.function.Predicate
;
import
java.util.function.Supplier
;
import
java.util.stream.Stream
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
/**
* Utility that can be used to invoke lambdas in a safe way. Primarily designed to help
* support generically typed callbacks where {@link ClassCastException class cast
* exceptions} need to be dealt with due to class erasure.
*
* @author Phillip Webb
* @since 2.0.0
*/
public
final
class
LambdaSafe
{
private
LambdaSafe
()
{
}
/**
* Start a call to a single callback instance, dealing with common generic type
* concerns and exceptions.
* @param callbackType the callback type (a {@link FunctionalInterface functional
* interface})
* @param callbackInstance the callback instance (may be a lambda)
* @param argument the primary argument passed to the callback
* @param additionalArguments any additional argument passed to the callback
* @param <C> the callback type
* @param <A> the primary argument type
* @return a {@link Callback} instance that can be invoked.
*/
public
static
<
C
,
A
>
Callback
<
C
,
A
>
callback
(
Class
<
C
>
callbackType
,
C
callbackInstance
,
A
argument
,
Object
...
additionalArguments
)
{
Assert
.
notNull
(
callbackType
,
"CallbackType must not be null"
);
Assert
.
notNull
(
callbackInstance
,
"CallbackInstance must not be null"
);
return
new
Callback
<>(
callbackType
,
callbackInstance
,
argument
,
additionalArguments
);
}
/**
* Start a call to a single callback instance, dealing with common generic type
* concerns and exceptions.
* @param callbackType the callback type (a {@link FunctionalInterface functional
* interface})
* @param callbackInstances the callback instances (elements may be lambdas)
* @param argument the primary argument passed to the callbacks
* @param additionalArguments any additional argument passed to the callbacks
* @param <C> the callback type
* @param <A> the primary argument type
* @return a {@link Callbacks} instance that can be invoked.
*/
public
static
<
C
,
A
>
Callbacks
<
C
,
A
>
callbacks
(
Class
<
C
>
callbackType
,
Collection
<?
extends
C
>
callbackInstances
,
A
argument
,
Object
...
additionalArguments
)
{
Assert
.
notNull
(
callbackType
,
"CallbackType must not be null"
);
Assert
.
notNull
(
callbackInstances
,
"CallbackInstances must not be null"
);
return
new
Callbacks
<
C
,
A
>(
callbackType
,
callbackInstances
,
argument
,
additionalArguments
);
}
/**
* Abstract base class for lambda safe callbacks.
*/
private
static
abstract
class
LambdaSafeCallback
<
C
,
A
,
SELF
extends
LambdaSafeCallback
<
C
,
A
,
SELF
>>
{
private
final
Class
<
C
>
callbackType
;
private
final
A
argument
;
private
final
Object
[]
additionalArguments
;
private
Log
logger
;
private
Filter
<
C
,
A
>
filter
=
new
GenericTypeFilter
<
C
,
A
>();
protected
LambdaSafeCallback
(
Class
<
C
>
callbackType
,
A
argument
,
Object
[]
additionalArguments
)
{
this
.
callbackType
=
callbackType
;
this
.
argument
=
argument
;
this
.
additionalArguments
=
additionalArguments
;
this
.
logger
=
LogFactory
.
getLog
(
callbackType
);
}
/**
* Use the specified logger source to report any lambda failures.
* @param loggerSource the logger source to use
* @return this instance
*/
public
SELF
withLogger
(
Class
<?>
loggerSource
)
{
return
withLogger
(
LogFactory
.
getLog
(
loggerSource
));
}
/**
* Use the specified logger to report any lambda failures.
* @param logger the logger to use
* @return this instance
*/
public
SELF
withLogger
(
Log
logger
)
{
Assert
.
notNull
(
logger
,
"Logger must not be null"
);
this
.
logger
=
logger
;
return
self
();
}
/**
* Use a specific filter to determine when a callback should apply. If not
* explicit filter is set filter will be attempted using the generic type on the
* callback type.
* @param filter the filter to use
* @return this instance
*/
public
SELF
withFilter
(
Filter
<
C
,
A
>
filter
)
{
Assert
.
notNull
(
filter
,
"Filter must not be null"
);
this
.
filter
=
filter
;
return
self
();
}
protected
final
<
R
>
InvocationResult
<
R
>
invoke
(
C
callbackInstance
,
Supplier
<
R
>
supplier
)
{
if
(
this
.
filter
.
match
(
this
.
callbackType
,
callbackInstance
,
this
.
argument
,
this
.
additionalArguments
))
{
try
{
return
InvocationResult
.
of
(
supplier
.
get
());
}
catch
(
ClassCastException
ex
)
{
if
(!
isLambdaGenericProblem
(
ex
))
{
throw
ex
;
}
logNonMachingType
(
callbackInstance
,
ex
);
}
}
return
InvocationResult
.
noResult
();
}
private
boolean
isLambdaGenericProblem
(
ClassCastException
ex
)
{
return
(
ex
.
getMessage
()
==
null
||
startsWithArgumentClassName
(
ex
.
getMessage
()));
}
private
boolean
startsWithArgumentClassName
(
String
message
)
{
Predicate
<
Object
>
startsWith
=
(
argument
)
->
argument
!=
null
&&
message
.
startsWith
(
argument
.
getClass
().
getName
());
return
startsWith
.
test
(
this
.
argument
)
||
Stream
.
of
(
this
.
additionalArguments
).
anyMatch
(
startsWith
);
}
private
void
logNonMachingType
(
C
callback
,
ClassCastException
ex
)
{
if
(
this
.
logger
.
isDebugEnabled
())
{
Class
<?>
expectedType
=
ResolvableType
.
forClass
(
this
.
callbackType
)
.
resolveGeneric
();
String
message
=
"Non-matching "
+
(
expectedType
==
null
?
"type"
:
ClassUtils
.
getShortName
(
expectedType
)
+
" type"
)
+
" for callback "
+
ClassUtils
.
getShortName
(
this
.
callbackType
)
+
": "
+
callback
;
this
.
logger
.
debug
(
message
,
ex
);
}
}
@SuppressWarnings
(
"unchecked"
)
private
SELF
self
()
{
return
(
SELF
)
this
;
}
}
/**
* Represents a single callback that can be invoked in a lambda safe way.
*
* @param <C> the callback type
* @param <A> the primary argument type
*/
public
static
final
class
Callback
<
C
,
A
>
extends
LambdaSafeCallback
<
C
,
A
,
Callback
<
C
,
A
>>
{
private
C
callbackInstance
;
private
Callback
(
Class
<
C
>
callbackType
,
C
callbackInstance
,
A
argument
,
Object
[]
additionalArguments
)
{
super
(
callbackType
,
argument
,
additionalArguments
);
this
.
callbackInstance
=
callbackInstance
;
}
/**
* Invoke the callback instance where the callback method returns void.
* @param invoker the invoker used to invoke the callback
*/
public
void
invoke
(
Consumer
<
C
>
invoker
)
{
invoke
(
this
.
callbackInstance
,
()
->
{
invoker
.
accept
(
this
.
callbackInstance
);
return
null
;
});
}
/**
* Invoke the callback instance where the callback method returns a result.
* @param invoker the invoker used to invoke the callback
* @param <R> the result type
* @return the result of the invocation (may be {@link InvocationResult#noResult}
* if the callback was not invoked)
*/
public
<
R
>
InvocationResult
<
R
>
invokeAnd
(
Function
<
C
,
R
>
invoker
)
{
return
invoke
(
this
.
callbackInstance
,
()
->
invoker
.
apply
(
this
.
callbackInstance
));
}
}
/**
* Represents a collection of callbacks that can be invoked in a lambda safe way.
*
* @param <C> the callback type
* @param <A> the primary argument type
*/
public
static
final
class
Callbacks
<
C
,
A
>
extends
LambdaSafeCallback
<
C
,
A
,
Callbacks
<
C
,
A
>>
{
private
Collection
<?
extends
C
>
callbackInstances
;
private
Callbacks
(
Class
<
C
>
callbackType
,
Collection
<?
extends
C
>
callbackInstances
,
A
argument
,
Object
[]
additionalArguments
)
{
super
(
callbackType
,
argument
,
additionalArguments
);
this
.
callbackInstances
=
callbackInstances
;
}
/**
* Invoke the callback instances where the callback method returns void.
* @param invoker the invoker used to invoke the callback
*/
public
void
invoke
(
Consumer
<
C
>
invoker
)
{
Function
<
C
,
InvocationResult
<
Void
>>
mapper
=
(
callbackInstance
)
->
invoke
(
callbackInstance
,
()
->
{
invoker
.
accept
(
callbackInstance
);
return
null
;
});
this
.
callbackInstances
.
stream
().
map
(
mapper
).
forEach
((
result
)
->
{
});
}
/**
* Invoke the callback instances where the callback method returns a result.
* @param invoker the invoker used to invoke the callback
* @param <R> the result type
* @return the results of the invocation (may be an empty stream if not callbacks
* could be called)
*/
public
<
R
>
Stream
<
R
>
invokeAnd
(
Function
<
C
,
R
>
invoker
)
{
Function
<
C
,
InvocationResult
<
R
>>
mapper
=
(
callbackInstance
)
->
invoke
(
callbackInstance
,
()
->
invoker
.
apply
(
callbackInstance
));
return
this
.
callbackInstances
.
stream
().
map
(
mapper
)
.
filter
(
InvocationResult:
:
hasResult
).
map
(
InvocationResult:
:
get
);
}
}
/**
* A filter that can be used to restrict when a callback is used.
*
* @param <C> the callback type
* @param <A> the primary argument type
*/
@FunctionalInterface
interface
Filter
<
C
,
A
>
{
/**
* Determine if the given callback matches and should be invoked.
* @param callbackType the callback type (the functional interface)
* @param callbackInstance the callback instance (the implementation)
* @param argument the primary argument
* @param additionalArguments any additional arguments
* @return if the callback matches and should be invoked
*/
boolean
match
(
Class
<
C
>
callbackType
,
C
callbackInstance
,
A
argument
,
Object
[]
additionalArguments
);
/**
* Return a {@link Filter} that allows all callbacks to be invoked.
* @param <C> the callback type
* @param <A> the primary argument type
* @return an "allow all" filter
*/
static
<
C
,
A
>
Filter
<
C
,
A
>
allowAll
()
{
return
(
callbackType
,
callbackInstance
,
argument
,
additionalArguments
)
->
true
;
}
}
/**
* {@link Filter} that matches when the callback has a single generic and primary
* argument is an instance of it.
*/
private
static
class
GenericTypeFilter
<
C
,
A
>
implements
Filter
<
C
,
A
>
{
@Override
public
boolean
match
(
Class
<
C
>
callbackType
,
C
callbackInstance
,
A
argument
,
Object
[]
additionalArguments
)
{
ResolvableType
type
=
ResolvableType
.
forClass
(
callbackType
,
callbackInstance
.
getClass
());
if
(
type
.
getGenerics
().
length
==
1
&&
type
.
resolveGeneric
()
!=
null
)
{
return
type
.
resolveGeneric
().
isInstance
(
argument
);
}
return
true
;
}
}
/**
* The result of a callback which may be a value, {@code null} or absent entirely if
* the callback wasn't suitable. Similar in design to {@link Optional} but allows for
* {@code null} as a valid value.
* @param <R> The result type
*/
public
final
static
class
InvocationResult
<
R
>
{
private
static
final
InvocationResult
<?>
NONE
=
new
InvocationResult
<
Object
>(
null
);
private
final
R
value
;
private
InvocationResult
(
R
value
)
{
this
.
value
=
value
;
}
/**
* Return true if a result in present.
* @return if a result is present
*/
public
boolean
hasResult
()
{
return
this
!=
NONE
;
}
/**
* Return the result of the invocation or {@code null} if the callback wasn't
* suitable.
* @return the result of the invocation or {@code null}
*/
public
R
get
()
{
return
this
.
value
;
}
/**
* Return the result of the invocation or the given fallback if the callback
* wasn't suitable.
* @param fallback the fallback to use when there is no result
* @return the result of the invocation or the fallback
*/
public
R
get
(
R
fallback
)
{
return
(
this
==
NONE
?
fallback
:
this
.
value
);
}
/**
* Create a new {@link InvocationResult} instance with the specified value.
* @param value the value (may be {@code null})
* @param <R> the result type
* @return an {@link InvocationResult}
*/
public
static
<
R
>
InvocationResult
<
R
>
of
(
R
value
)
{
return
new
InvocationResult
<
R
>(
value
);
}
/**
* Return an {@link InvocationResult} instance representing no result.
* @param <R> the result type
* @return an {@link InvocationResult}
*/
@SuppressWarnings
(
"unchecked"
)
public
static
<
R
>
InvocationResult
<
R
>
noResult
()
{
return
(
InvocationResult
<
R
>)
NONE
;
}
}
}
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/package-info.java
0 → 100644
View file @
798882bd
/*
* Copyright 2012-2018 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.
*/
/**
* Contains miscellaneous utility classes.
*/
package
org
.
springframework
.
boot
.
util
;
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java
View file @
798882bd
...
...
@@ -21,15 +21,12 @@ import java.util.Collection;
import
java.util.Collections
;
import
java.util.List
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.BeanFactory
;
import
org.springframework.beans.factory.BeanFactoryAware
;
import
org.springframework.beans.factory.ListableBeanFactory
;
import
org.springframework.beans.factory.config.BeanPostProcessor
;
import
org.springframework.
core.ResolvableTyp
e
;
import
org.springframework.
boot.util.LambdaSaf
e
;
import
org.springframework.core.annotation.AnnotationAwareOrderComparator
;
import
org.springframework.util.Assert
;
...
...
@@ -45,9 +42,6 @@ import org.springframework.util.Assert;
public
class
WebServerFactoryCustomizerBeanPostProcessor
implements
BeanPostProcessor
,
BeanFactoryAware
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
WebServerFactoryCustomizerBeanPostProcessor
.
class
);
private
ListableBeanFactory
beanFactory
;
private
List
<
WebServerFactoryCustomizer
<?>>
customizers
;
...
...
@@ -75,45 +69,13 @@ public class WebServerFactoryCustomizerBeanPostProcessor
return
bean
;
}
private
void
postProcessBeforeInitialization
(
WebServerFactory
bean
)
{
for
(
WebServerFactoryCustomizer
<?>
customizer
:
getCustomizers
())
{
Class
<?>
type
=
ResolvableType
.
forClass
(
WebServerFactoryCustomizer
.
class
,
customizer
.
getClass
())
.
getGeneric
().
resolve
(
WebServerFactory
.
class
);
if
(
type
.
isInstance
(
bean
))
{
invokeCustomizer
(
customizer
,
bean
);
}
}
}
@SuppressWarnings
({
"rawtypes"
,
"unchecked"
})
private
void
invokeCustomizer
(
WebServerFactoryCustomizer
customizer
,
WebServerFactory
webServerFactory
)
{
try
{
customizer
.
customize
(
webServerFactory
);
}
catch
(
ClassCastException
ex
)
{
String
msg
=
ex
.
getMessage
();
if
(
msg
==
null
||
msg
.
startsWith
(
webServerFactory
.
getClass
().
getName
()))
{
// Possibly a lambda-defined WebServerFactoryCustomizer which we could not
// resolve the
// generic WebServerFactory type for
logLambdaDebug
(
customizer
,
ex
);
}
else
{
throw
ex
;
}
}
}
private
void
logLambdaDebug
(
WebServerFactoryCustomizer
<?>
customizer
,
ClassCastException
ex
)
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Non-matching WebServerFactory type for WebServerFactoryCustomizer: "
+
customizer
,
ex
);
}
@SuppressWarnings
(
"unchecked"
)
private
void
postProcessBeforeInitialization
(
WebServerFactory
webServerFactory
)
{
LambdaSafe
.
callbacks
(
WebServerFactoryCustomizer
.
class
,
getCustomizers
(),
webServerFactory
)
.
withLogger
(
WebServerFactoryCustomizerBeanPostProcessor
.
class
)
.
invoke
((
customizer
)
->
customizer
.
customize
(
webServerFactory
));
}
private
Collection
<
WebServerFactoryCustomizer
<?>>
getCustomizers
()
{
...
...
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java
0 → 100644
View file @
798882bd
/*
* Copyright 2012-2018 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
.
boot
.
util
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.stream.Stream
;
import
org.apache.commons.logging.Log
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.boot.util.LambdaSafe.Filter
;
import
org.springframework.boot.util.LambdaSafe.InvocationResult
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
junit
.
Assert
.
fail
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
ArgumentMatchers
.
contains
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
verifyZeroInteractions
;
/**
* Tests for {@link LambdaSafe}.
*
* @author Phillip Webb
*/
public
class
LambdaSafeTests
{
@Rule
public
ExpectedException
thrown
=
ExpectedException
.
none
();
@Test
public
void
callbackWhenCallbackTypeIsNullShouldThrowException
()
{
this
.
thrown
.
expect
(
IllegalArgumentException
.
class
);
this
.
thrown
.
expectMessage
(
"CallbackType must not be null"
);
LambdaSafe
.
callback
(
null
,
new
Object
(),
null
);
}
@Test
public
void
callbackWhenCallbackInstanceIsNullShouldThrowException
()
{
this
.
thrown
.
expect
(
IllegalArgumentException
.
class
);
this
.
thrown
.
expectMessage
(
"CallbackInstance must not be null"
);
LambdaSafe
.
callback
(
Object
.
class
,
null
,
null
);
}
@Test
public
void
callbackInvokeWhenNoGenericShouldInvokeCallback
()
{
NonGenericCallback
callbackInstance
=
mock
(
NonGenericCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
NonGenericCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeWhenHasGenericShouldInvokeCallback
()
{
StringCallback
callbackInstance
=
mock
(
StringCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeWhenHasResolvableGenericMatchShouldInvokeCallback
()
{
StringBuilderCallback
callbackInstance
=
mock
(
StringBuilderCallback
.
class
);
StringBuilder
argument
=
new
StringBuilder
(
"foo"
);
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeWhenHasResolvableGenericNonMatchShouldNotInvokeCallback
()
{
GenericCallback
<?>
callbackInstance
=
mock
(
StringBuilderCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verifyZeroInteractions
(
callbackInstance
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeWhenLambdaMismatchShouldSwallowException
()
{
GenericCallback
<
StringBuilder
>
callbackInstance
=
(
s
)
->
{
fail
(
"Should not get here"
);
};
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeWhenLambdaMismatchOnDifferentArgumentShouldSwallowException
()
{
GenericMultiArgCallback
<
StringBuilder
>
callbackInstance
=
(
n
,
s
,
b
)
->
{
fail
(
"Should not get here"
);
};
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericMultiArgCallback
.
class
,
callbackInstance
,
argument
)
.
invoke
((
c
)
->
c
.
handle
(
1
,
argument
,
false
));
}
@Test
public
void
callbackInvokeAndWhenNoGenericShouldReturnResult
()
{
NonGenericFactory
callbackInstance
=
mock
(
NonGenericFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
123
);
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
NonGenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
.
hasResult
()).
isTrue
();
assertThat
(
result
.
get
()).
isEqualTo
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenHasGenericShouldReturnResult
()
{
StringFactory
callbackInstance
=
mock
(
StringFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
123
);
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
.
hasResult
()).
isTrue
();
assertThat
(
result
.
get
()).
isEqualTo
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenReturnNullShouldReturnResult
()
{
StringFactory
callbackInstance
=
mock
(
StringFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
null
);
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
.
hasResult
()).
isTrue
();
assertThat
(
result
.
get
()).
isNull
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenHasResolvableGenericMatchShouldReturnResult
()
{
StringBuilderFactory
callbackInstance
=
mock
(
StringBuilderFactory
.
class
);
StringBuilder
argument
=
new
StringBuilder
(
"foo"
);
given
(
callbackInstance
.
handle
(
any
(
StringBuilder
.
class
))).
willReturn
(
123
);
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
assertThat
(
result
.
hasResult
()).
isTrue
();
assertThat
(
result
.
get
()).
isEqualTo
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult
()
{
GenericFactory
<?>
callbackInstance
=
mock
(
StringBuilderFactory
.
class
);
String
argument
=
"foo"
;
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
.
hasResult
()).
isFalse
();
verifyZeroInteractions
(
callbackInstance
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenLambdaMismatchShouldSwallowException
()
{
GenericFactory
<
StringBuilder
>
callbackInstance
=
(
s
)
->
{
fail
(
"Should not get here"
);
return
123
;
};
String
argument
=
"foo"
;
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
.
hasResult
()).
isFalse
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException
()
{
GenericMultiArgFactory
<
StringBuilder
>
callbackInstance
=
(
n
,
s
,
b
)
->
{
fail
(
"Should not get here"
);
return
123
;
};
String
argument
=
"foo"
;
InvocationResult
<
Integer
>
result
=
LambdaSafe
.
callback
(
GenericMultiArgFactory
.
class
,
callbackInstance
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
1
,
argument
,
false
));
assertThat
(
result
.
hasResult
()).
isFalse
();
}
@Test
public
void
callbacksInvokeWhenNoGenericShouldInvokeCallbacks
()
{
NonGenericCallback
callbackInstance
=
mock
(
NonGenericCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callbacks
(
NonGenericCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenHasGenericShouldInvokeCallback
()
{
StringCallback
callbackInstance
=
mock
(
StringCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callbacks
(
GenericCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenHasResolvableGenericMatchShouldInvokeCallback
()
{
StringBuilderCallback
callbackInstance
=
mock
(
StringBuilderCallback
.
class
);
StringBuilder
argument
=
new
StringBuilder
(
"foo"
);
LambdaSafe
.
callbacks
(
GenericCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
callbackInstance
).
handle
(
argument
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenHasResolvableGenericNonMatchShouldNotInvokeCallback
()
{
GenericCallback
<?>
callbackInstance
=
mock
(
StringBuilderCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callbacks
(
GenericCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
null
));
verifyZeroInteractions
(
callbackInstance
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenLambdaMismatchShouldSwallowException
()
{
GenericCallback
<
StringBuilder
>
callbackInstance
=
(
s
)
->
{
fail
(
"Should not get here"
);
};
String
argument
=
"foo"
;
LambdaSafe
.
callbacks
(
GenericCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
argument
));
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenLambdaMismatchOnDifferentArgumentShouldSwallowException
()
{
GenericMultiArgCallback
<
StringBuilder
>
callbackInstance
=
(
n
,
s
,
b
)
->
{
fail
(
"Should not get here"
);
};
String
argument
=
"foo"
;
LambdaSafe
.
callbacks
(
GenericMultiArgCallback
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invoke
((
c
)
->
c
.
handle
(
1
,
argument
,
false
));
}
@Test
public
void
callbacksInvokeAndWhenNoGenericShouldReturnResult
()
{
NonGenericFactory
callbackInstance
=
mock
(
NonGenericFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
123
);
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
NonGenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
containsExactly
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenHasGenericShouldReturnResult
()
{
StringFactory
callbackInstance
=
mock
(
StringFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
123
);
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
containsExactly
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenReturnNullShouldReturnResult
()
{
StringFactory
callbackInstance
=
mock
(
StringFactory
.
class
);
String
argument
=
"foo"
;
given
(
callbackInstance
.
handle
(
"foo"
)).
willReturn
(
null
);
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
containsExactly
((
Integer
)
null
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenHasResolvableGenericMatchShouldReturnResult
()
{
StringBuilderFactory
callbackInstance
=
mock
(
StringBuilderFactory
.
class
);
StringBuilder
argument
=
new
StringBuilder
(
"foo"
);
given
(
callbackInstance
.
handle
(
any
(
StringBuilder
.
class
))).
willReturn
(
123
);
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
containsExactly
(
123
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult
()
{
GenericFactory
<?>
callbackInstance
=
mock
(
StringBuilderFactory
.
class
);
String
argument
=
"foo"
;
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
isEmpty
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenLambdaMismatchShouldSwallowException
()
{
GenericFactory
<
StringBuilder
>
callbackInstance
=
(
s
)
->
{
fail
(
"Should not get here"
);
return
123
;
};
String
argument
=
"foo"
;
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
(
c
).
handle
(
argument
));
assertThat
(
result
).
isEmpty
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException
()
{
GenericMultiArgFactory
<
StringBuilder
>
callbackInstance
=
(
n
,
s
,
b
)
->
{
fail
(
"Should not get here"
);
return
123
;
};
String
argument
=
"foo"
;
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericMultiArgFactory
.
class
,
Collections
.
singleton
(
callbackInstance
),
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
1
,
argument
,
false
));
assertThat
(
result
).
isEmpty
();
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbacksInvokeWhenMultipleShouldInvokeSuitable
()
{
List
<
GenericFactory
<?>>
callbackInstances
=
new
ArrayList
<>();
GenericFactory
<
String
>
callback1
=
(
s
)
->
1
;
GenericFactory
<
CharSequence
>
callback2
=
(
s
)
->
2
;
GenericFactory
<
StringBuilder
>
callback3
=
(
s
)
->
3
;
StringFactory
callback4
=
mock
(
StringFactory
.
class
);
given
(
callback4
.
handle
(
any
(
String
.
class
))).
willReturn
(
4
);
StringBuilderFactory
callback5
=
mock
(
StringBuilderFactory
.
class
);
given
(
callback5
.
handle
(
any
(
StringBuilder
.
class
))).
willReturn
(
5
);
callbackInstances
.
add
(
callback1
);
callbackInstances
.
add
(
callback2
);
callbackInstances
.
add
(
callback3
);
callbackInstances
.
add
(
callback4
);
callbackInstances
.
add
(
callback5
);
String
argument
=
"foo"
;
Stream
<
Integer
>
result
=
LambdaSafe
.
callbacks
(
GenericFactory
.
class
,
callbackInstances
,
argument
)
.
invokeAnd
((
c
)
->
c
.
handle
(
argument
));
assertThat
(
result
).
containsExactly
(
1
,
2
,
4
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackWithFilterShouldUseFilter
()
{
GenericCallback
<?>
callbackInstance
=
mock
(
StringBuilderCallback
.
class
);
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
withFilter
(
Filter
.
allowAll
()).
invoke
((
c
)
->
c
.
handle
(
null
));
verify
(
callbackInstance
).
handle
(
null
);
}
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
callbackWithLoggerShouldUseLogger
()
{
Log
logger
=
mock
(
Log
.
class
);
given
(
logger
.
isDebugEnabled
()).
willReturn
(
true
);
GenericCallback
<
StringBuilder
>
callbackInstance
=
(
s
)
->
{
fail
(
"Should not get here"
);
};
String
argument
=
"foo"
;
LambdaSafe
.
callback
(
GenericCallback
.
class
,
callbackInstance
,
argument
)
.
withLogger
(
logger
).
invoke
((
c
)
->
c
.
handle
(
argument
));
verify
(
logger
).
debug
(
contains
(
"Non-matching CharSequence type for callback "
+
"LambdaSafeTests.GenericCallback"
),
any
(
Throwable
.
class
));
}
interface
NonGenericCallback
{
void
handle
(
String
argument
);
}
interface
GenericCallback
<
T
extends
CharSequence
>
{
void
handle
(
T
argument
);
}
interface
StringCallback
extends
GenericCallback
<
String
>
{
}
interface
StringBuilderCallback
extends
GenericCallback
<
StringBuilder
>
{
}
interface
GenericMultiArgCallback
<
T
extends
CharSequence
>
{
void
handle
(
Integer
numner
,
T
argument
,
Boolean
bool
);
}
interface
NonGenericFactory
{
Integer
handle
(
String
argument
);
}
interface
GenericFactory
<
T
extends
CharSequence
>
{
Integer
handle
(
T
argument
);
}
interface
StringFactory
extends
GenericFactory
<
String
>
{
}
interface
StringBuilderFactory
extends
GenericFactory
<
StringBuilder
>
{
}
interface
GenericMultiArgFactory
<
T
extends
CharSequence
>
{
Integer
handle
(
Integer
numner
,
T
argument
,
Boolean
bool
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment