I have the following PatternLayout:
public class EscapedEnhancedPatternLayout extends EnhancedPatternLayout {
#Override
public String format(LoggingEvent event) {
return StringEscapeUtils.escapeJava(super.format(event));
}
}
but this escapes full logging row.
I want to have something like this but only for message.
but LoggingEvent class has not setMessage and setRenderedMessage methods.
And I don't see copy constructor at LoggingEvent. If LoggingEvent had copy constructor I can inherited from LoggingEvent and override methods mentioned below.
Please advise me how to solve my issue.
You're right, there is no LoggingEvent(LoggingEvent other) constructor, but you can pass the event's values to the LoggingEvent constructor in your format method like this:
#Override
public String format(LoggingEvent event) {
Object msgObj = event.getMessage();
LoggingEvent newEvent = new LoggingEvent(
event.getFQNOfLoggerClass(),
event.getLogger(), event.getTimeStamp(),
event.getLevel(),
StringEscapeUtils.escapeJava(msgObj != null ? msgObj.toString() : null),
event.getThreadName(),
event.getThrowableInformation(),
event.getNDC(),
event.getLocationInformation(),
event.getProperties());
return super.format(newEvent);
}
This will create a new LoggingEvent from the old one with all values set. The StringEscapeUtils.escapeJava method can now modify the the message without affecting the other properties and you can still use super.format
An alternative approach could be to create a customized LogEventFactory. A LogEventFactory is used to generate LogEvents. Applications may replace the standard LogEventFactory by setting the value of the system property Log4jLogEventFactory to the name of the custom LogEventFactory class.
The method that will be called to create a instance of LogEvent is as follows:
LogEvent createEvent(String loggerName,
org.apache.logging.log4j.Marker marker,
String fqcn,
org.apache.logging.log4j.Level level,
org.apache.logging.log4j.message.Message data,
List<Property> properties,
Throwable t)
and DefaultLogEventFactory is the basic implementation for log4j. In your case you could extend the basic implementation and escape the message after which you call the default implementation. It would become something like this:
public class MyCustomLogEventFactory extends DefaultLogEventFactory {
/**
* Creates a log event.
*
* #param loggerName The name of the Logger.
* #param marker An optional Marker.
* #param fqcn The fully qualified class name of the caller.
* #param level The event Level.
* #param data The Message.
* #param properties Properties to be added to the log event.
* #param t An optional Throwable.
* #return The LogEvent.
*/
#Override
public LogEvent createEvent(final String loggerName, final Marker marker,
final String fqcn, final Level level, final Message data,
final List<Property> properties, final Throwable t) {
super.createEvent(loggerName, marker, fqcn, level, StringEscapeUtils.escapeJava(data != null ? data.toString() : null), properties, t);
}
}
Related
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.
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());
I am trying to create a subclass of an abstract class in bytebuddy and want to override the constructor with my own function. I can not make it work with defineConstructor.
Superclass:
public abstract class AbstractDMTable {
protected HashMap<String, DMEntry<?>> parameterMap;
public DMEntry<?> getParameter(String paramName) {
if (parameterMap.containsKey(paramName))
return parameterMap.get(paramName);
return null;
}...
Subclass:
public class DMTable_DEBUGOUT extends AbstractDMTable {
/**
* Table entry
* prints the value of the specified parameter
*/
public DMEntry<DMEntry<?>> DEBUG_PARAM;
/**
* Table entry
* execution interval of the step handler (s)
*/
public DMEntry<Double> EXEC_INTERVAL;
/**
* Table entry
* active / not active status of this subsystem
*/
public DMEntry<Boolean> IS_ACTIVE;
/**
* Standard constructor. Creates a new table and initializes all entry fields with all entry values set to {#code null}
*/
public DMTable_DEBUGOUT() {
super();
DEBUG_PARAM = new DMEntry<>();
parameterMap.put("DEBUG_PARAM", DEBUG_PARAM);
EXEC_INTERVAL = new DMEntry<>();
parameterMap.put("EXEC_INTERVAL", EXEC_INTERVAL);
IS_ACTIVE = new DMEntry<>();
parameterMap.put("IS_ACTIVE", IS_ACTIVE);
}
}
My ByteBuddy:
DynamicType.Builder<? extends AbstractDMTable> subsystem = new ByteBuddy().subclass(AbstractDMTable.class)
.name("DMTable_" + name).defineConstructor(Collections.<Class<AbstractDMTable>> emptyList(), Visibility.PUBLIC);
for (Entry<String, Pair<String, String>> p : t.getValue().entrySet()) {
subsystem.defineField(p.getKey(), this.createSubSystemEntry(p).getClass(), Visibility.PUBLIC);
}
// subsystem.defineConstructor(Arrays.<Class<AbstractDMTable>>
// asList(int.class), Visibility.PUBLIC);
return subsystem.make().load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER).getLoaded();
The Error:
defineConstructor(ModifierContributor.ForMethod...) in the type
DynamicType.Builder<AbstractDMTable> is not applicable for the
arguments (List<Class<?>>, Visibility) DynamicDatabaseGenerator.java
line 66 Java Problem
You are using the default constructor strategy which imitates the super class constructors. The subclass method is overloaded to avoid this duplicate definition by using a different constructor strategy that does not imitate the super class.
Also, you should update Byte Buddy, this way you would get a better error message.
Here's a really simple class:
static public class Bean1
{
final private String name;
final private Bean1 parent;
private int favoriteNumber;
public String getName() { return this.name; }
public Bean getParent() { return this.parent; }
public int getFavoriteNumber() { return this.favoriteNumber; }
public void setFavoriteNumber(int i) { this.favoriteNumber = i; }
}
What I would like to do is to bind some UI components to a BeanAdapter<Bean1> (see com.jgoodies.binding.beans.BeanAdapter) so that if the BeanAdapter points to Bean1 bean1, then I can display
bean1.name (blank if null)
bean1.parent.name (blank if null or if bean1.parent is null)
bean1.favoriteNumber
The fields name and favoriteNumber are easy, but I'm confused about how to display the parent name. It looks like BeanAdapter only lets me bind to properties which exist directly in Bean1. But this is poor modularity and it forces me to add getter/setter functions every time I want to bind to a new aspect of the bean.
What I would like to do is write a helper class which knows how to access a bean, and am confused how to get it to work properly with Bean1 and BeanAdapter.
I'm sorry if this question is not more clear, I don't know the vocabulary and am a little hazy on the concepts of binding.
The problem here is that binding works in both ways: from model to ui, and from ui to model.
In your case, how would you deal with someone entering information for the first time in a textfield that's binded to parent.name? Would you create a parent on the fly? Would you give an error?
If you know what to do in that situation (e.g. create a parent with that name), you could use a com.jgoodies.binding.value.AbstractConverter to convert a Bean1 to a String:
public class ParentNameConverter extends AbstractConverter {
/**
* Converts a value from the subject to the type or format used
* by this converter.
*
* #param subjectValue the subject's value
* #return the converted value in the type or format used by this converter
*/
public Object convertFromSubject(Object subjectValue) { ... }
/**
* Sets a new value on the subject, after converting to appropriate type
* or format
*
* #param newValue the ui component's value
*/
public void setValue(Object newValue) { ... }
}
You can use this converter the same way you use a normal ValueModel:
Bindings.bind(uifield,"value",
new ParentNameConverter(beanAdapter.getValueModel("parent")));
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.