Spring Integration CompositeFileListFilter - java

I am using CompositeFileListFilter to add two filters. Firstly, I want to execute AbstractPersistentFileListFilter with the default implementation, thereby protecting it from duplication.
Second, I use my own implementation, which checks the database for the existence of a file, protecting me from duplicates in the event of a system restart
How can this approach be released? So that the default implementation of AbstractPersistentFileListFilter with the internal memory of the MetadataStore is executed first
The goal is to reduce database calls to check for the existence of a file. Perhaps there is a better approach to the solution. Thanks for any help!
FtpConfiguration.java
#Bean
CompositeFileListFilter<FTPFile> getCompositeFileListFilter() {
CompositeFileListFilter<FTPFile> compositeFileListFilter = new CompositeFileListFilter<>();
compositeFileListFilter.addFilters(new CustomFileFilter(messageRepo));
return compositeFileListFilter;
}
#Bean
public IntegrationFlow ftpIntegrationFlow() {
return IntegrationFlows.from(
Ftp.inboundStreamingAdapter(template())
.filter(getCompositeFileListFilter())
.remoteDirectory("."),
e -> e.poller(Pollers.fixedDelay(500).advice(advice())))
.transform(new StreamTransformer("UTF-8"))
.handle(messageService::unmarshall)
.get();
}
CustomFileFilter.java
#Component
#Log4j2
public class CustomFileFilter implements FileListFilter<FTPFile> {
private final MessageRepo messageRepo;
public CustomFileFilter(MessageRepo messageRepo) {
this.messageRepo = messageRepo;
}
#Override
public List<FTPFile> filterFiles(FTPFile[] files) {
return null;
}
#Override
public boolean accept(FTPFile file) {
String fileName = file.getName();
log.info("file filter get name: {}", fileName);
Integer fileCheck = messageRepo.checkExistsMessage(fileName);
log.info("fileCheck: {}", fileCheck);
return fileCheck != 1;
}
#Override
public boolean supportsSingleFileFiltering() {
return true;
}
}

Use the ChainFileListFilter instead:
/**
* The {#link CompositeFileListFilter} extension which chains the result
* of the previous filter to the next one. If a filter in the chain returns
* an empty list, the remaining filters are not invoked.
*
* #param <F> The type that will be filtered.
*
* #author Artem Bilan
* #author Gary Russell
* #author Cengis Kocaurlu
*
* #since 4.3.7
*
*/
public class ChainFileListFilter<F> extends CompositeFileListFilter<F> {
https://docs.spring.io/spring-integration/docs/current/reference/html/file.html#file-reading
Starting with version 4.3.7, a ChainFileListFilter (an extension of CompositeFileListFilter) has been introduced to allow scenarios when subsequent filters should only see the result of the previous filter. (With the CompositeFileListFilter, all filters see all the files, but it passes only files that have passed all filters). ...

Related

Handler method name in SpringAmqp interceptors

I use spring amqp with multi-method listeners, like this:
#RabbitListener(queues = PLATFORM_COMMAND_QUEUE)
#Component
public class PlatformListener {
#RabbitHandler
public Response<GetAllPlatformsResponse> getAllPlatforms(GetAllPlatforms command) {
...
return Response.ok(GetAllPlatformsResponse.create(allPlatforms));
}
#RabbitHandler
public Response<PlatformResponse> getPlatform(GetPlatformCommand command) {
...
return Response.ok(platformService.getPlatform(command));
}
}
And I wand add specific header with handler name (getAllPlatforms, getPlatform) for all response messages. For that, i try add setAfterReceivePostProcessors and setBeforeSendReplyPostProcessors, but they do not provide any information about handler methods.
factory.setBeforeSendReplyPostProcessors(message -> {
Method targetMethod = message.getMessageProperties().getTargetMethod();
assert targetMethod == null;
return message;
});
How can i get method name and add it to reply message header?
It's not currently possible; as the javadocs state, that property is only populated for method-level #RabbitListener.
/**
* The target method when using a method-level {#code #RabbitListener}.
* #return the method.
* #since 1.6
*/
public Method getTargetMethod() {
return this.targetMethod;
}
Given some changes to the architecture over the years, I think it should now be possible to populate this also for class-level listeners. Please open a new feature suggestion and I'll take a look at adding it.

conditional stubbing in Mockito given invocation order of multiple methods

Is there a clean way to change a mock's method behavior based on other method's invocation?
Example of code under test, service will be mocked by Mockito in the test:
public Bar foo(String id) {
Bar b = service.retrieveById(id);
boolean flag = service.deleteById(id);
b = service.retrieveById(id); //this should throw an Exception
return b;
}
Here, we would like service.retrieveById to return an object, unless service.delete has been called.
Chaining behaviours could work in this simple case, but it doesn'd consider the invocation of the other method deleteById (imagine refactoring).
when(service.retrieveById(any())).
.thenReturn(new Bar())
.thenThrow(new RuntimeException())
I am wondering for example if it's possible to implement an Answer object which can detect whether deleteById has been invoked. Or if there is a totally different approach which would make the test cleaner.
In my eyes, this is a good example of over-engeneering mock objects.
Don't try to make your mocks behave like "the real thing".
That is not what mocking should be used for when writing tests.
The test is not about Service itself, it's about some class that makes use of it.
If Service either returns something for a given Id, or raises an exception when there is no result, make 2 individual test cases!
we can't foresee the reason of the refactoring.. maybe there will be n call to retrieve before the delete.. So this is really about tying the two methods behavior together.
Yes, and someone could add another twelve methods that all influence the outcome of deleteById. Will you be keeping track?
Use stubbing only to make it run.
Consider writing a fake if Service is rather simple and doesn't change much. Remember mocking is just one tool. Sometimes there are alternatives.
Considering what I've just said, this might send you mixed messages but since StackOverflow was down for a while and I'm currently working heavily with Mockito myself, I spent some time with your other question:
I am wondering for example if it's possible to implement an Answer object which can detect whether deleteById has been invoked.
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.function.Supplier;
import static java.util.Objects.requireNonNull;
/**
* An Answer that resolves differently depending on a specified condition.
*
* <p>This implementation is NOT thread safe!</p>
*
* #param <T> The result type
*/
public class ConditionalAnswer <T> implements Answer<T> {
/**
* Create a new ConditionalAnswer from the specified result suppliers.
*
* <p>On instantiation, condition is false</p>
*
* #param whenConditionIsFalse The result to supply when the underlying
condition is false
* #param whenConditionIsTrue The result to supply when the underlying
condition is true
* #param <T> The type of the result to supply
* #return A new ConditionalAnswer
*/
public static <T> ConditionalAnswer<T> create (
final Supplier<T> whenConditionIsFalse,
final Supplier<T> whenConditionIsTrue) {
return new ConditionalAnswer<>(
requireNonNull(whenConditionIsFalse, "whenConditionIsFalse"),
requireNonNull(whenConditionIsTrue, "whenConditionIsTrue")
);
}
/**
* Create a Supplier that on execution throws the specified Throwable.
*
* <p>If the Throwable turns out to be an unchecked exception it will be
* thrown directly, if not it will be wrapped in a RuntimeException</p>
*
* #param throwable The throwable
* #param <T> The type that the Supplier officially provides
* #return A throwing Supplier
*/
public static <T> Supplier<T> doThrow (final Throwable throwable) {
requireNonNull(throwable, "throwable");
return () -> {
if (RuntimeException.class.isAssignableFrom(throwable.getClass())) {
throw (RuntimeException) throwable;
}
throw new RuntimeException(throwable);
};
}
boolean conditionMet;
final Supplier<T> whenConditionIsFalse;
final Supplier<T> whenConditionIsTrue;
// Use static factory method instead!
ConditionalAnswer (
final Supplier<T> whenConditionIsFalse,
final Supplier<T> whenConditionIsTrue) {
this.whenConditionIsFalse = whenConditionIsFalse;
this.whenConditionIsTrue = whenConditionIsTrue;
}
/**
* Set condition to true.
*
* #throws IllegalStateException If condition has been toggled already
*/
public void toggle () throws IllegalStateException {
if (conditionMet) {
throw new IllegalStateException("Condition can only be toggled once!");
}
conditionMet = true;
}
/**
* Wrap the specified answer so that before it executes, this
* ConditionalAnswer is toggled.
*
* #param answer The ans
* #return The wrapped Answer
*/
public Answer<?> toggle (final Answer<?> answer) {
return invocation -> {
toggle();
return answer.answer(invocation);
};
}
#Override
public T answer (final InvocationOnMock invocation) throws Throwable {
return conditionMet ? whenConditionIsTrue.get() : whenConditionIsFalse.get();
}
/**
* Test whether the underlying condition is met
* #return The state of the underlying condition
*/
public boolean isConditionMet () {
return conditionMet;
}
}
I wrote some tests to make it work. This is how it would look applied to the Service example:
#Test
void conditionalTest (
#Mock final Service serviceMock, #Mock final Bar barMock) {
final var id = "someId"
// Create shared, stateful answer
// First argument: Untill condition changes, return barMock
// Second: After condition has changed, throw Exception
final var conditional = ConditionalAnswer.create(
() -> barMock,
ConditionalAnswer.doThrow(new NoSuchElementException(someId)));
// Whenever retrieveById is invoked, the call will be delegated to
// conditional answer
when(service.retrieveById(any())).thenAnswer(conditional);
// Now we can define, what makes the condition change.
// In this example it is service#delete but it could be any other
// method on any other class
// Option 1: Easy but ugly
when(service.deleteById(any())).thenAnswer(invocation -> {
conditional.toggle();
return Boolean.TRUE;
});
// Option 2: Answer proxy
when(service.deleteById(any()))
.thenAnswer(conditional.toggle(invocation -> Boolean.TRUE));
// Now you can retrieve by id as many times as you like
assertSame(barMock, serviceMock.retrieveById(someId));
assertSame(barMock, serviceMock.retrieveById(someId));
assertSame(barMock, serviceMock.retrieveById(someId));
assertSame(barMock, serviceMock.retrieveById(someId));
assertSame(barMock, serviceMock.retrieveById(someId));
// Until
assertTrue(serviceMock.deleteById(someId));
// NoSuchElementException
serviceMock.retrieveById(someId)
}
}
The test above might contain errors (I used some classes from the project that I am currently working on).
Thanks for the challenge.
You can use Mockito.verify() to check whether deleteById was called or not:
Mockito.verify(service).deleteById(any());
You can also use Mockito.InOrder for orderly verification (I have not tested the below code):
InOrder inOrder = Mockito.inOrder(service);
inOrder.verify(service).retrieveById(any());
inOrder.verify(service).deleteById(any());
inOrder.verify(service).retrieveById(any());

WatchEventType.DELETE doesn't seem to work

what I would like to do is to track the files removed and apply certain logic around this (get the id and update the entities). I've found that we can pass a list of watch events inside the channel adapter including
FileReadingMessageSource.WatchEventType.DELETE
but when I remove the file from the folder I do not see any events triggered and the transformer is never being applied
#Bean
public IntegrationFlow integrationFlow(FileToMovieTransformer fileToMovieTransformer) {
return this.integrationFlowBuilder()
.transform(fileToMovieTransformer)
.channel(movieHandlerChannel())
.get();
}
private IntegrationFlowBuilder integrationFlowBuilder() {
return IntegrationFlows.from(
Files.inboundAdapter(new File(localFilmFolder))
.autoCreateDirectory(true)
.useWatchService(true)
.watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE)
.patternFilter("*.xml"),
e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
));
}
I would say that you treat DELETE wrong way:
/**
* Directory entry deleted.
*
* <p> When a directory is registered for this event then the {#link WatchKey}
* is queued when it is observed that an entry is deleted or renamed out of
* the directory. The event {#link WatchEvent#count count} for this event
* is always {#code 1}.
*/
public static final WatchEvent.Kind<Path> ENTRY_DELETE =
new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);
So, there is already nothing to emit as a message to downstream. We definitely talk here about a FileReadingMessageSource. But with DELETE there is nothing to read any more. Am I missing anything?
And here is what we have in the Docs so far:
The ENTRY_DELETE events have effect for the ResettableFileListFilter implementations and, therefore, their files
are provided for the remove() operation.
This means that (when this event is enabled), filters such as the AcceptOnceFileListFilter will have the file removed,
meaning that, if a file with the same name appears, it will pass the filter and be sent as a message.
Therefore to achieve whatever you would like to do in case of DELETE event, you need to implement ResettableFileListFilter and together with SimplePatternFileListFilter you should composite them into the CompositeFileListFilter.
When file is deleted , that DELETE event is emitted and we end up with the logic like:
if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
if (getFilter() instanceof ResettableFileListFilter) {
((ResettableFileListFilter<File>) getFilter()).remove(file);
}
Where the mentioned CompositeFileListFilter definitely implements this ResettableFileListFilter one and will delegate to your own implementation.
thanks for #Artem, here is the complete code sample that seems to work well for me
private IntegrationFlowBuilder integrationFlowBuilder() {
final List<FileListFilter<File>> defaultFilters = new ArrayList<>(2);
defaultFilters.add(new IgnoreHiddenFileListFilter());
defaultFilters.add(new AcceptOnceFileListFilter<>());
defaultFilters.add(new SimplePatternFileListFilter("*.xml"));
defaultFilters.add(myCustomRemovalFilter);
CompositeFileListFilter fileListFilter = new CompositeFileListFilter<>(defaultFilters);
return IntegrationFlows.from(
Files.inboundAdapter(new File(localFilmFolder))
.autoCreateDirectory(true)
.filter(fileListFilter)
.useWatchService(true)
.watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE),
e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
));
}
and the filter looks like
#Component
public class MyCustomRemovalFilter implements ResettableFileListFilter<File> {
private static final Logger LOGGER = LogManager.getLogger(MyCustomRemovalFilter.class);
#Override
public boolean remove(File xmlFile) {
if (xmlFile == null) {
return true;
}
// TODO you own on removal logic
}
#Override
public List<File> filterFiles(File[] files) {
if (files == null || files.length == 0) {
return Collections.emptyList();
}
return Arrays.asList(files);
}
}

When is JMXBean initialised

IMEI I am new to MXbeans. I want to understand when is the MXBean actually initialized, in the application which I am supporting we have a notification system and I can not see my MXBean in JConsole until there is some notification arriving. Here is a code of my MXBean.
package mecomaany.instrumentation;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import BulkCMIRP_MxBean;
import SoapIRPLogger;
/**
* This dynamic MBean exposes a method to return the 10 latest Basic CM
* operations.
*
* #author eshtrom
*
*/
public class BasicCMIRP_MxBean implements DynamicMBean{
private static final String CLASS_NAME = BasicCMIRP_MxBean.class.getCanonicalName();
private static final String MX_BEAN_NAME = BasicCMIRP_MxBean.class.getCanonicalName() + ":Type=BasicCMIRP_MxBean";
private static final String BEAN_DESCRIPTION = "Instrumentation bean for SOAP Basic CM IRP.";
private static final int NUM_OPERATIONS_TO_RECORD = 10;
private final ArrayList<String> basicCMOperations = new ArrayList<String>();
/**
* Register the bean. This is a best effort attempt. If registration fails
* we'll report it but nothing more.
*/
public BasicCMIRP_MxBean() {
registerMxBean();
}
/**
* Attempt to unregister and clean up the MX beans.
*/
public void destroy() {
basicCMOperations.clear();
unregisterMxBean();
}
/**
* This method returns a description of this bean to the JMX interface. The
* description is just a list of names of the currently stored attributes.
*/
public synchronized MBeanInfo getMBeanInfo() {
final MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[0];
final MBeanOperationInfo[] operations = { new MBeanOperationInfo("getBasicCMInstrumentation", "Get instrumentation Basic CM IRP bean.", null, "String[]",
MBeanOperationInfo.INFO) };
return new MBeanInfo(this.getClass().getName(), BEAN_DESCRIPTION, attributes, null, operations, null);
}
/**
* Callback to execute methods exposed by this dynamic MBean.
*/
public Object invoke(final String actionName, final Object[] params, final String[] signature) throws MBeanException, ReflectionException {
SoapIRPLogger.enter(CLASS_NAME, "invoke");
if (actionName != null) {
if (actionName.equals("getBulkCMInstrumentation")) {
return getBasicCMInstrumentation();
}
}
SoapIRPLogger.exit(CLASS_NAME, "invoke");
throw new ReflectionException(new NoSuchMethodException(actionName));
}
/**
* Construct a human readable very of the last 10 operations and return it.
*
* #return string array as an object.
*/
private Object getBasicCMInstrumentation() {
SoapIRPLogger.enter(CLASS_NAME, "getBasicCMInstrumentation");
String[] result = new String[basicCMOperations.size()];
int index = 0;
for (String operation : basicCMOperations) {
result[index] = operation;
index++;
}
SoapIRPLogger.exit(CLASS_NAME, "getBasicCMInstrumentation");
return result;
}
/**
* No attributes are writable so this method will throw an exception.
*/
public void setAttribute(final Attribute arg0) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
throw new AttributeNotFoundException("All attributes on this bean are read only.");
}
/**
* No attributes are writable so this method will return an empty list.
*/
public AttributeList setAttributes(final AttributeList arg0) {
return new AttributeList();
}
public Object getAttribute(final String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
throw new AttributeNotFoundException("No attributes are defined on this MX bean.");
}
/**
* No attributes are readable so this method will return an empty list.
*/
public AttributeList getAttributes(final String[] attributes) {
return new AttributeList();
}
/**
* Add or update and instrumentation attribute. A null attribute name will
* be ignored.
*
* #param name
* #param value
*/
public void updateInstrumentationAttibute(final String name, final String value) {
// The only attribute that this bean supports is Bulk CM operations.
if (name.compareTo("BasicCM_Operations") == 0) {
basicCMOperations.add(value);
// We'll only record a maximum of 10 operations. If we exceed the
// max, remove the oldest.
if (basicCMOperations.size() > NUM_OPERATIONS_TO_RECORD) {
basicCMOperations.remove(0);
}
}
}
public ObjectName getBeanName() throws MalformedObjectNameException, NullPointerException {
// Construct the ObjectName for the MBean we will register
return new ObjectName(MX_BEAN_NAME);
}
/**
* Register the bean.
*/
protected void registerMxBean() {
try {
ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.getBeanName());
} catch (Exception e) {
SoapIRPLogger.exception(CLASS_NAME, "Constructor", "Failed to register BulkCMIRP_MxBean management beans.", e);
}
}
protected void unregisterMxBean() {
try {
ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.getBeanName());
} catch (Exception e) {
// Suppress exceptions, we're closing down anyway.
}
}
}
Loner;
Your MXBean should be visible in JConsole as soon as you construct it, since the constructor calls registerMxBean() which registers the MBean with the platform MBeanServer.
Assuming your JConsole is already running when the MBean is registered, JConsole's view of the MBean will be dictated by the first instance of the MBeanInfo that is generated on registration. Since you coded this as a DynamicMBean, I wonder if your intent was to periodically modify the MBeanInfo, but be aware that once a JConsole connection has retrieved the MBeanInfo for a registered bean, it will not refresh it. If the MBeanInfo changes, you must closed the connection in JConsole and open it again.
Consequently, your issue may be outside the code you have supplied, or more simply put, when is the instance of BasicCMIRP_MxBean created ?
Your comment about not seeing the bean until notifications start arriving makes me wonder if you mean that:
A. You cannot see the MBean until notifications start arriving, in which case I would assume that there is some activation code that creates the instance when a [the first ?] notification arrives, or
B. What you mean is that you cannot see specific properties of the MBean until notifications start arriving.
Perhaps you could clarify the larger picture here.
Some additional observations that may be unrelated:
The MBeanInfo you are generating specifies that the one and only operation is called getBasicCMInstrumentation (basic), but your invoke handler only attempts to decode an operation called getBulkCMInstrumentation (bulk). JConsole is supplied the MBeanInfo in order to render the operations so the console believes that the operation is called basic but the MBean will only respond to a request called bulk.
The signature for method getBasicCMInstrumentation returns an Object but what the code really returns is a String[]. This may work because your MBeanInfo specifies that a String[] is returned, but for consistency and clarity I would change the method signature.
//Nicholas

How can I mock a method in easymock that shall return one of its parameters?

public Object doSomething(Object o); which I want to mock. It should just return its parameter. I tried:
Capture<Object> copyCaptcher = new Capture<Object>();
expect(mock.doSomething(capture(copyCaptcher)))
.andReturn(copyCatcher.getValue());
but without success, I get just an AssertionError as java.lang.AssertionError: Nothing captured yet. Any ideas?
Well, the easiest way would be to just use the Capture in the IAnswer implementation... when doing this inline you have to declare it final of course.
MyService mock = createMock(MyService.class);
final Capture<ParamAndReturnType> myCapture = new Capture<ParamAndReturnType>();
expect(mock.someMethod(capture(myCapture))).andAnswer(
new IAnswer<ParamAndReturnType>() {
#Override
public ParamAndReturnType answer() throws Throwable {
return myCapture.getValue();
}
}
);
replay(mock)
This is probably the most exact way, without relying on some context information. This does the trick for me every time.
I was looking for the same behavior, and finally wrote the following :
import org.easymock.EasyMock;
import org.easymock.IAnswer;
/**
* Enable a Captured argument to be answered to an Expectation.
* For example, the Factory interface defines the following
* <pre>
* CharSequence encode(final CharSequence data);
* </pre>
* For test purpose, we don't need to implement this method, thus it should be mocked.
* <pre>
* final Factory factory = mocks.createMock("factory", Factory.class);
* final ArgumentAnswer<CharSequence> parrot = new ArgumentAnswer<CharSequence>();
* EasyMock.expect(factory.encode(EasyMock.capture(new Capture<CharSequence>()))).andAnswer(parrot).anyTimes();
* </pre>
* Created on 22 juin 2010.
* #author Remi Fouilloux
*
*/
public class ArgumentAnswer<T> implements IAnswer<T> {
private final int argumentOffset;
public ArgumentAnswer() {
this(0);
}
public ArgumentAnswer(int offset) {
this.argumentOffset = offset;
}
/**
* {#inheritDoc}
*/
#SuppressWarnings("unchecked")
public T answer() throws Throwable {
final Object[] args = EasyMock.getCurrentArguments();
if (args.length < (argumentOffset + 1)) {
throw new IllegalArgumentException("There is no argument at offset " + argumentOffset);
}
return (T) args[argumentOffset];
}
}
I wrote a quick "how to" in the javadoc of the class.
Hope this helps.
Captures are for testing the values passed to the mock afterwards. If you only need a mock to return a parameter (or some value calculated from the parameter), you just need to implement IAnswer.
See "Remi Fouilloux"s implementation if you want a reusable way of passing paramter X back, but ignore his use of Capture in the example.
If you just want to inline it like "does_the_trick"s example, again, the Capture is a red herring here. Here is the simplified version:
MyService mock = createMock(MyService.class);
expect(mock.someMethod(anyObject(), anyObject()).andAnswer(
new IAnswer<ReturnType>() {
#Override
public ReturnType answer() throws Throwable {
// you could do work here to return something different if you needed.
return (ReturnType) EasyMock.getCurrentArguments()[0];
}
}
);
replay(mock)
Based on #does_the_trick and using lambdas, you can now write the following:
MyService mock = EasyMock.createMock(MyService.class);
final Capture<ParamAndReturnType> myCapture = EasyMock.newCapture();
expect(mock.someMethod(capture(myCapture))).andAnswer(() -> myCapture.getValue());
or without capture as #thetoolman suggested
expect(mock.someMethod(capture(myCapture)))
.andAnswer(() -> (ParamAndReturnType)EasyMock.getCurrentArguments()[0]);
Um, if I understand your question correctly I think you may be over complicating it.
Object someObject = .... ;
expect(mock.doSomething(someObject)).andReturn(someObject);
Should work just fine. Remember you are supplying both the expected parameter and returne value. So using the same object in both works.

Categories