How to create custom java annotation to log method parameters - java

I am writting JavaEE application and I would like to use and create custom annotation, which will log data, when annotated method will be called. All I would like to do is, that when annotated method is called, code iterate through all passed method parameters and writes to standard output parameter keys and values.
Some example:
public class Test {
#LogMethodData
public int sum(int first, int second) {
return first + second;
}
}
I would like to achieve, that when a custom metod will be annotated with #LogMethodData, that code behind will take care and log passed method parameters to standard output (something like "Method data: first - 4, second - 5" if parameter first contains value 4 and parameter second contains value 5), independent from number of passed parameters to methods.
I would be very happy if someone could help me with that, because I have been already searching for a solution, but I didn't found anything usefull. And last, I am not familiar with this things.
Regards,
Dahakka

There is no need to define your own Annotation, you can use the #Interceptors Annotation in the EE Container as explained here.
#Interceptors(LoggingInterceptor.class)
Within the Interceptor you'll get a Context that contains your Parameters
public class LoggingInterceptor {
...
#AroundInvoke
public Object modifyGreeting(InvocationContext ctx) throws Exception {
....
Object[] parameters = ctx.getParameters();
try {
return ctx.proceed();
} catch (Exception e) {
logger.warning("Error calling ctx.proceed in modifyGreeting()");
return null;
}
}
}
another example : here

Related

First stub is called when adding an additional stub

I have the following object which I want to test:
public class MyObject {
#Inject
Downloader downloader;
public List<String> readFiles(String[] fileNames) {
List<String> files = new LinkedList<>();
for (String fileName : fileNames) {
try {
files.add(downloader.download(fileName));
} catch (IOException e) {
files.add("NA");
}
}
return files;
}
}
This is my test:
#UseModules(mockTest.MyTestModule.class)
#RunWith(JukitoRunner.class)
public class mockTest {
#Inject Downloader downloader;
#Inject MyObject myObject;
private final String[] FILE_NAMES = new String[] {"fail", "fail", "testFile"};
private final List<String> EXPECTED_FILES = Arrays.asList("NA", "NA", "mockContent");
#Test
public void testException() throws IOException {
when(downloader.download(anyString()))
.thenThrow(new IOException());
when(downloader.download("testFile"))
.thenReturn("mockContent");
assertThat(myObject.readFiles(FILE_NAMES))
.isEqualTo(EXPECTED_FILES);
}
public static final class MyTestModule extends TestModule {
#Override
protected void configureTest() {
bindMock(Downloader.class).in(TestSingleton.class);
}
}
}
I am overwriting the anyString() matcher for a specific argument. I am stubbing the download() method so that it returns a value for a specific argument and otherwise throws an IOException which gets handled by MyObject.readFiles.
The weird thing here is that the second stub (downloader.download("testFile")) throws the IOException set in the first stub (downloader.download(anyString())). I have validated that by throwing a different exception in my first stub.
Can someone explain me why the exception is thrown when adding an additional stub? I thought that creating a stub does not call the method/other stubs.
The problem is that when you write
when(downloader.download("testFile")).thenReturn("mockContent");
the first thing to be called is downloader.download, which you've already stubbed to throw an exception.
The solution is to use the slightly more versatile stubbing syntax that Mockito provides. This syntax has the advantage that it doesn't call the actual method when stubbing.
doThrow(IOException.class).when(downloader).download(anyString());
doReturn("mock content").when(downloader).download("test file");
I have listed other advantages of this second syntax, in my answer here
I thought that creating a stub does not call the method/other stubs.
This assumption is wrong, because stubbing is calling the mocks methods. Your test methods are still plain java!
Since stubbing for anyString will overwrite stubbing for any specific string you will either have to write two tests or stub for two specific arguments:
when(downloader.download("fail")).thenThrow(new IOException());
when(downloader.download("testFile")).thenReturn("mockContent");
Mockito is a very sophisticated piece of code that tries its best so that you can write
when(downloader.download(anyString())).thenThrow(new IOException());
which means “when the downloaders mock download method is called with anyString argument thenThrow an IOException” (i.e. it can be read from left to right).
However, since the code is still plain java, the call sequence actually is:
String s1 = anyString(); // 1
String s2 = downloader.download(s1); // 2
when(s2).thenThrow(new IOException()); // 3
Behind the scenes, Mockito needs to do this:
register an ArgumentMatcher for any String argument
register a method call download on the downloader mock where the argument is defined by the previously registered ArgumentMatcher
register an action for the previously registered method call on a mock
If you now call
... downloader.download("testFile") ...
the downloader mock checks whether there is an action register for "testFile" (there is, since there is already an action for any String) and accordingly throws the IOException.
Your 2nd mock statement is getting overriden by the first mock statement (because both mock statements are passing a String argument). If you want to cover try as well as catch back through your mock test then write 2 different test cases.

Picketlink: How to get annotation parameters and the name of the function decorated when using #Secures?

I'm trying to define and use a custom security binding type called BasicRolesAllowed, as has been demonstrated in the Picketlink quickstarts here.
The only different between my type the ones in the quickstart, is that my annotation has to accept an array of strings (we want to secure methods using not just one but possibly combinations of roles), and thus my annotation is defined thus:
public #interface BasicRolesAllowed {
String[] value() default {};
}
Following the quickstart, I've tried to define how this decorator authenticates as such:
#Secures
#BasicRolesAllowed
public boolean doAdminCheck(Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
/*
Sample usage of #BasicRolesAllowed is like:
#BasicRolesAllowed(value = RoleConstants.CREATE_USER)
TODO: need to get these from the #BasicRolesAllowed annotation instance/usage
*/
String[] requiredRoles = {};// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
And as can be seen in the snippet, the trick part is:
String[] requiredRoles = {};// get these from annotation
How do I get the string constants passed to the annotation on the decorated method so I can use them in looking up roles?
Some Hints:
There's an answer to a similar question here, but the problem is that in that solution; one needs to know the name of the decorated function or class - which in my case is impossible given that the decorator will be used just about anywhere, and I don't know how to get these via the method shown in the Picketlink quickstart.
Also, the solution only shows how to obtain the value passed to an annotation expecting only 1 string - maybe I could try using values(), but the above limitation still stands in my way.
Thanks in advance to anyone who can help.
Thanks to #pedroigor over at #picketlink (freenode), the solution can be gleaned from an example of such a use-case in the picketlink quickstart here. In that file, a method getAnnotation() is defined, which has the signature:
private <T extends Annotation> T getAnnotation(InvocationContext invocationContext, Class<T> annotationType)
So, using this method, I'm able to introspect and obtain the values passed to my annotation as can be seen in my new implementation of the roles checking method here:
#Secures
#BasicRolesAllowed
public boolean hasBasicRolesCheck(InvocationContext invocationContext, Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
The essential modifications being:
I had to pass an instance of the invocation context InvocationContext invocationContext by adding this as a parameter to my method definition (CDI magic takes care of all else I hear).
I then obtain the annotation instance by calling:
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
And then get the values/parameters passed to the annotation thus:
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
This solves my problem :-)

Can I ignore aspect of a method while mocking it using Mockito?

I have a class with a few methods advised through an input validation aspect (validates whether all input parameters are not-null/non-empty strings).
I am facing an issue while writing test case for them and want to verify if this is indeed a bad design issue.
Here's a very simplified version of my class:
public class A {
public String one(String word) {
// Some actions
String val = two(word2);
// Some more actions
}
protected String two(String word) {
// Some actions
}
}
Now while writing test cases for one() I use Mockito and want to mock calls to two(). So I use:
#Spy
A a;
#Test
void test() {
doReturn("Bye").when(A).two(Mockito.anyString());
a.one("hello");
// Some validations
}
This test fails as the: doReturn() line fails with input being empty for two().
Should I not mock two() or can I make this work somehow?
Edit:
Adding a more specific example related to the two methods being present in two different classes as requested:
Create a page through a WebService. This builds a putRequest, executes it and returns a response.
public class AUtility implements BaseUtility {
public Response create(Params params) {
try {
PutMethod putRequest = buildPUTRequest(params.getAttr1(), params.getAttr2());
return Utils.buildResponse(client.executeMethod(putRequest),
params.getAttr3(),
params.getAttr4());
} catch (Exception e) {
throw new AppException(e);
}
}
}
The put request marshals the data into a file to write it through the HttpClient
private PutMethod buildPUTRequest(final String url, final Object obj) throws IOException, JAXBException {
// Create a temp file to store the stream
File tempFile = File.createTempFile(APPLICATION_LABEL, XML_LABEL);
decoder.marshal(obj, tempFile);
// Build the put method
return putMethod;
}
XMLMarshaller
public interface XMLDecoder implement Decoder {
public void marshal(Object obj, File tempFile) throws IOException, JAXBException {
// Perform marshalling operations
}
}
The test fails on line2 with the inputs being null.
#Test
public void createPageParamsHttpException() throws HttpException, IOException, JAXBException {
expectedException.expect(AppException.class);
doNothing().when(decoder).marshal(Mockito.anyString(), Mockito.any(File.class));
doThrow(HttpException.class).when(client).executeMethod(Mockito.any(HttpMethod.class));
Params params = new Params(new Application(),
APPLICATION_URL_LABEL,
SITE_NAME_LABEL,
URL_WITHOUT_HTTP_N_HTML);
utility.createPage(params);
}
Any idea how should I proceed for the same?
You don't want to do this.
You are inherently changing the behavior of the class. If you change what two() does, how do you know that one() will do what it's supposed to do in production?
If you truly want to do this, you should extract the behavior of two() into another top level class, and then inject the dependency into A. Then you can mock this dependency and you don't have to worry about going to the trouble of creating a partial mock for A.
In a similar vein, if you must keep two in the same class (because it's behavior is part of the same responsibility that is assigned to A - see the Single Responsibility Principle - why is it public?
The reason you are having trouble is because you are violating the SRP, see my note above. You said this:
This builds a putRequest, executes it and returns a response.
You should not be trying to test the behavior of all three of those things at the same time. Ultimately, this method does not really do anything. The buildPUTRequest method does, and shouldn't be in a class called AUtility, it should be in a class RequestFactory. Then, you would want to test the Utils.buildResponse method, except that shouldn't be in a class called Utils, it should be in a class called Responder or something... and this method ABSOLUTELY should not be static.
Work on naming your classes better things, and if you can't come up with a good name, that means the class probably does too much and should be refactored. And a method that wraps the work in two other methods doesn't need to be unit tested. Integration tested, perhaps, but that's another story.

arguments for hasPermission in a generic controller

I am trying implement a generic controller class where each method has a structure similar to this:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_#this.class.name')")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
return new ModelAndView("privado/"+this.entity.getClass().getName()+"/cadastra", "command", this.entity.getClass().newInstance());
}
I am having trouble with the annotation PreAuthorize. the name for the permissionhave this structure: _. right now, I am getting a 403 Error when I try access the view mapped by the method. I also tried other variations like:
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
or
#PreAuthorize("hasPermission(#user, 'cadastra_#this.getClass().getName()')")
but with the same result. Anyone knows the right way to accomplish this?
UPDATE
I try call this function inside the methods from controller secured by this tag PreAuthorize:
private void expressionParser() {
System.out.println("expressionHandler()");
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("'cadastra_'+#this.class.name");
String message = (String) expression.getValue();
System.out.println("Message is " + message);
}
and when I run the application and open the view should be mapped by a method from controller, like this one:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
this.expressionParser();
return new ModelAndView("privado/"+this.entityClass.getName()+"/cadastra", "command", this.entityClass.newInstance());
}
No message is displayed on the console. So, I am thinking my application somehow aren't calling the methods from my generic controller. Am I right? If so, how I fix this?
My derived controllers follow this structure:
#Controller
#RequestMapping(value="usuario")
public class UsuarioController extends controller<Usuario> {
public UsuarioController() {
super(Usuario.class);
}
}
So you have difficulties with dynamic construction of permission name in the form of [methodName]_[classFullName] in SpEL expression.
See what SpEL documentation says about #this variable below
The variable #this is always defined and refers to the current evaluation object
(against which unqualified references are resolved).
Based on the documentation and a bit digging in the code the actual object the #this represents should be in your case an instance of org.springframework.security.access.expression.method.MethodSecurityExpressionRoot class. The class contains several helpful methods among others also getThis() method that returns the target object on which the secured method (a method annotated with #PreAuthorize) is being invoked.
Armed with this knowledge it should not be a big deal to construct the expression you require. In case of method named "cadastra", it should be as follows.
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.class.name)")
Hopefully it will also work correctly for secured methods inherited from a base class.
So, I solved this issue with this approach:
1) Adding a new method to my generic controller, where I return the name of the class:
public String getName() {
String expressao = entityClass.getName();
String nome_classe = new String();
StringTokenizer st = new StringTokenizer(expressao, ".");
while (st.hasMoreTokens()) {
nome_classe = st.nextToken();
}
return nome_classe;
}
2) Inside the annotation, I use the returned value by this method and concatenate the result with the constant string (using the notation described by the user #pgjecek in this topic):
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
and now it1s working perfectly.

Mockito changing the default value for wrapper classes

I am trying to mock a bean that has an Integer property. The method I am testing checks to see if the initial value of that property is null, if it is it sets it. According to the mockito docs:
By default, for all methods that return value, mock returns null, an empty collection or appropriate primitive/primitive wrapper value (e.g: 0, false, ... for int/Integer, boolean/Boolean, ...)
So my property is set to 0 by mockito and my test fails. Is there a way to override this default behavior?
EDIT
Jeff Bowman gave a great answer, and I would like to follow his advice... however I'm not sure how. Here is some of the method I am trying to test:
public class ViewBeanBuilder {
#Inject
private ViewBean viewBean;
public void buildViewBean() {
....
for (Model model : getModels()) {
if (viewBean.getAmount() == null || model.getAmount() < viewBean.getAmount()) {
viewBean.setAmount(model.getAmount());
}
}
....
}
}
My problem is, if I don't mock the ViewBean then I get a null pointer exception. However, when I do mock it I have the problems already discussed. Am I taking the wrong approach? Is there another way to do this?
One thought I had was to put a getter around my viewBean:
public class ViewBeanBuilder {
#Inject
private ViewBean viewBean;
public void buildViewBean() {
....
for (Model model : getModels()) {
if (getViewBean().getAmount() == null || model.getAmount() < getViewBean().getAmount()) {
viewBean.setAmount(model.getAmount());
}
}
....
}
private ViewBean getViewBean() {
return viewBean;
}
}
Then in my test I could use:
#InjectMocks
private ViewBeanBuilder builder = new ViewBeanBuilder();
#Test
private void testBuilder() {
ViewBean viewBean = new ViewBean();
when(builder.getViewBean()).thenReturn(viewBean);
builder.buildViewBean();
....
}
I'll probably try this tomorrow. But is this a valid approach?
EDIT
Using the when also failed...
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be a method call on a mock.
For example:
when(mock.getArticles()).thenReturn(articles);
First of all, don't mock data objects (objects that contain significant state). Beans are data objects. Instead, create a real bean, put values into it, and use that bean in your tests.
That said, Mockito mocks have no implementation, and do not behave differently between bean methods and other methods:
YourBean bean = Mockito.mock(YourBean.class); // A mock acting like YourBean.
bean.getIntegerValue(); // Returns 0 by default.
bean.setIntegerValue(50); //
bean.getIntegerValue(); // Still returns 0, not 50.
// The call to setIntegerValue is
verify(bean).setIntegerValue(50); // recorded; Mockito just doesn't
// match the getter and setter.
To override those default values, stub using when and thenReturn statements. You can use as many as you like, and thenReturn accepts as many parameters as you'd like. The last value will be repeated indefinitely.
YourBean bean = Mockito.mock(YourBean.class); // A mock acting like YourBean.
when(bean.getIntegerValue())
.thenReturn(1) // Calls to getIntegerValue()
.thenReturn(3, 5) // in sequence will return
.thenReturn(7); // (1, 3, 5, 7, 7, 7...).
This also works for your simple case to stub null instead of 0:
YourBean bean = Mockito.mock(YourBean.class);
when(bean.getIntegerValue()).thenReturn(null);
Note that the only way to make getIntegerValue return the value most recently set using setIntegerValue is to write Answers, which is tricky and verbose. This is part of the reason mocking data objects makes little sense: The logic to make a mock bean is complicated, where the use of a real bean is simple and authentic to your test.

Categories