am working on a Jenkins plugin and evaluating unit testing software at the same time, and came upon a learning opportunity. The software wrote a test case for this method-
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
// indicates that this builder can be used with all
// kinds of project types
return true;
}
Seems pretty straightforward. The test case doesn't compile though, and I have not been able to figure out how to fix it from my limited knowledge of using wildcards. My current attempt-
AbstractProject ap = new FreeStyleProject(null, null);;
Assert.assertTrue(testedObject.isApplicable(ap));
(FreeStyleProject extends AbstractProject)
This gives the error message
The method isApplicable(Class) in the type FitnesseBuilder.DescriptorImpl is not applicable for the arguments (AbstractProject)
I have tried a variety of types to pass to that argument, but cannot seem to get it to accept anything. Anyone feel like giving me a quick lesson?
You need to pass the Class<T> object, not an instance of that class:
// AbstractProject ap = new FreeStyleProject(null, null);
Assert.assertTrue(testedObject.isApplicable(FreeStyleProject.class));
Of course, FreeStyleProject class needs to extend AbstractProject (since the first line of your current code compiles, it does that already).
Try Assert.assertTrue(testedObject.isApplicable(FreeStyleProject.class)); as it takes an instance of Class rather than AbstractProject
Related
I have been working on a small logging/debug library for my Java projects. I know there are many good ones already out there but I want to learn from doing one myself.
One method I want to have as part of this library is the ability to find out which method you are in at any one time, similar to __func__ in C++. Most of the time it'd be fine to just use the StackTrace to find this, since you often don't need more than the name (and/or declaring class) of the method, but I want to have the ability to get the method as an instance of the java.lang.reflect.Method
The easiest way of doing this is by simply doing
Method currentMethod = new Object() {}.getClass().getEnclosingMethod();
which will work just fine, but I can't figure out a way to do the same without creating that 'new Object() {}' within the method itself. Ideally I'd prefer if I could make a simple
Method currentMethod = _method();
to get the same result but with my current approach it'd just get me the Method-instance of _method itself.
Is there any known method to achieve this? If there isn't that's fine, but it'd be nice to have one.
EDIT: A lot of suggestions I receive, such as this post, provide mostly answers that provide you with the NAME of the method. It would be possible to use that (and the Class info gained in the same way) to find the Method, but only if the class in question has only one method with that name. Methods with the same name but different arguments cannot be identified with this!
This can be done using a StackWalker (since Java 9). It does not directly
provide a Method but enough information to create one.
Here the basic idea, can be improved (e.g. better Exception(s)):
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.Method;
public class MethodFinder {
public static Method method() {
return StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).walk(stream ->
stream
.filter(MethodFinder::notThisClass)
.findFirst()
.map(MethodFinder::frameToMethod))
.orElseThrow();
}
private static boolean notThisClass(StackFrame frame) {
return frame.getDeclaringClass() != MethodFinder.class;
}
private static Method frameToMethod(StackFrame frame) {
var cl = frame.getDeclaringClass();
try {
return cl.getDeclaredMethod(frame.getMethodName(), frame.getMethodType().parameterArray());
} catch (NoSuchMethodException | SecurityException ex) {
throw new RuntimeException(ex);
}
}
}
To be used like Method myself = MethodFinder.method().
I can make an RPC call in Java like this:
final FlowHandle flowHandle = rpcOps.startFlowDynamic(
TransferObligation.Initiator.class,
linearId, newLender, true);
The first parameter is the class to invoke and the next three are arguments to the class passed via varargs.
As we can see by the class definition the args match and the call works fine:
public Initiator(UniqueIdentifier linearId, Party newLender, Boolean anonymous) {
this.linearId = linearId;
this.newLender = newLender;
this.anonymous = anonymous;
}
However, if I add or remove args from the constructor the code will still compile and I will only notice at runtime (or integration testing - assuming I have enough test coverage).
The same applies if I pass the wrong args in the first place in the RPC call.
e.g. the following compiles fine but gives a runtime error:
final FlowHandle flowHandle = rpcOps.startFlowDynamic(
TransferObligation.Initiator.class,
linearId, newLender, true, 100000L, "Random String");
Is it possible to check for these errors with something other than test cases?
e.g. Static analysis using a custom IDEA code inspection or a custom SonarQube rule
EDIT: It appears that the Kotlin API has a type safe way of starting the flows (using inline reified extension functions) that the Java API does not, so I have removed the kotlin tag and updated the references to Java examples.
Along with CordaRPCOps.startFlowDynamic which as you mentioned has a varargs parameter for the Flow constructor arguments, there is CordaRPCOps.startFlow methods, which is basically nothing more than extension function for type-safe invocation of flows.
CordaRPSOps.kt
I have this method that I am using in a NetBeans plugin:
public static SourceCodeFile getCurrentlyOpenedFile() {
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
/* Get Java file currently displaying in the IDE if there is an opened project */
if (openedProject != null) {
TopComponent activeTC = TopComponent.getRegistry().getActivated();
DataObject dataLookup = activeTC.getLookup().lookup(DataObject.class);
File file = FileUtil.toFile(dataLookup.getPrimaryFile()); // Currently opened file
// Check if the opened file is a Java file
if (FilenameUtils.getExtension(file.getAbsoluteFile().getAbsolutePath()).equalsIgnoreCase("java")) {
return new SourceCodeFile(file);
} else {
return null;
}
} else {
return null;
}
}
Basically, using NetBeans API, it detects the file currently opened by the user in the IDE. Then, it loads it and creates a SourceCodeFile object out of it.
Now I want to unit test this method using JUnit. The problem is that I don't know how to test it.
Since it doesn't receive any argument as parameter, I can't test how it behaves given wrong arguments. I also thought about trying to manipulate openedProject in order to test the method behaviour given some different values to that object, but as far as I'm concernet, I can't manipulate a variable in JUnit that way. I also cannot check what the method returns, because the unit test will always return null, since it doesn't detect any opened file in NetBeans.
So, my question is: how can I approach the unit testing of this method?
Well, your method does take parameters, "between the lines":
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
basically fetches the object to work on.
So the first step would be to change that method signature, to:
public static SourceCodeFile getCurrentlyOpenedFile(Project project) {
...
Of course, that object isn't used, except for that null check. So the next level would be to have a distinct method like
SourceCodeFile lookup(DataObject dataLookup) {
In other words: your real problem is that you wrote hard-to-test code. The "default" answer is: you have to change your production code, to make easier to test.
For example by ripping it apart, and putting all the different aspects into smaller helper methods.
You see, that last method lookup(), that one takes a parameter, and now it becomes (somehow) possible to think up test cases for this. Probably you will have to use a mocking framework such as Mockito to pass mocked instances of that DataObject class within your test code.
Long story short: there are no detours here. You can't test your code (in reasonable ways) as it is currently structured. Re-structure your production code, then all your ideas about "when I pass X, then Y should happen" can work out.
Disclaimer: yes, theoretically, you could test the above code, by heavily relying on frameworks like PowerMock(ito) or JMockit. These frameworks allow you to contol (mock) calls to static methods, or to new(). So they would give you full control over everything in your method. But that would basically force your tests to know everything that is going on in the method under test. Which is a really bad thing.
I'm building a parser for a compiler, and what I would like to have a class (static) method for each term the parser finds. This method should return a regular expression which can be used to determine whether the token that the Scanner provided is that term and express it as a boolean value. It should be a static method that all derivative classes are guaranteed to have.
Unfortunately, the Java language does not take kindly to this kind of method extension. The code would either not compile, or reference the wrong edition of the method. I'm sure I'll come up with a few workarounds myself, probably involving reflection or a careful HashMap; but this isn't the first time I've run into a problem like this one, and I'm curious. Has anyone else here come up with a solution that provides passable extensibility of static methods?
Okay, let met clarify. I am not looking for a why-doesn't-this-compile, nor am I looking for a how-do-I-make-this-work. I am looking for a method by which I can check a method, which does not require the class to yet be instantiated, which can be relied upon to exist for any extending class. And, it needs to work in my weapon of choice for this project, that is, Java.
As we all know that what I am discussing is in fact not a static method (pardon me, I thought I was clear about that), there is no code to show you; and what I do have is largely tangential. What I have come up with is this, in an abstract constructor:
public Item(String token) {
if(!check(token)) {
throw new MismatchException(this.getClass() + " cannot be instantiated for \"" + token + "\"");
}
this.setData(derive(token));
}
public abstract boolean check(String token);
Meanwhile, creation of each token (and in this instance, addition to the abstract parse tree) goes like this (though I believe that it's still in need of a little polishing):
for(Sting token : tokenList) {
for(Class<?> cls : buildables) {
try {
Constructor constructor = cls.getConstructor(String.class);
result.add((Buildable)constructor.newInstance(c.toString()));
} catch(InvocationTargetException ex) {
//"MismatchException" is my own creation, for this exact purpose
if(ex.getTargetException() instanceof MismatchException)
continue;
} catch (Exception ex) {
//Again, a point for polishing:
ex.printStackTrace();
continue;
}
}
}
So, the problem is solved, as long as all extensions fit those parameters. If you have another suggestion on how this can be done, I'm game for it.
As an addendum, for those who really want to see the code of my current project, you can grab everything completed (and pushed) from github at https://github.com/MichaelEricOberlin/Builder-Tutorial . It's of course meant to be public anyway.
Edit (David Wallace):
So we have a class Foo with a method public static void bar() - or possibly a different signature. Then we have subclasses RedFoo, GreenFoo and BlueFoo each with its own version of public static void bar(). Obviously, this is illegal in Java. The question is how to work around this.
I solved it more or less as follows:
A class Symbol for terminal symbols (one RegexSymbol suffices) and nonterminal symbols (NonTerminalSymbol, SequenceSymbol, AlternativesSymbol, ...). The child classes may be package local.
A class Token with a field Symbol, and a start and end position: a symbol occurrence.
A class Grammar which has factory methods for symbols.
Grammar myGrammar = new Grammar() {
Symbol op = regex("\\+|-|\\*|/");
Symbol number = regex("\\d+");
Symbol expr = nonterminal();
{
define(expr,
alternatives(seq(number, op, expr),
number));
}
};
Not sure, how this maps on your case. But I separate grammar (Symbol) from the AST abstract syntax trees or parsed token occurrences.
I have to develop an "generic" wigdet for a GWT/GXT project and to do so I need to create an instance of an object which type is unknown. I found an approach that works perfectly in dev mode but as soon as I try to compile my project and deploy it I get an Only class literals may be used as arguments to GWT.create() error.
Here is a sample of what I do:
public class GenericEditableGrid<M> extends Grid<M>{
private final ToolBar toolBar = new ToolBar();
private final TextButton newItemButton = new TextButton();
protected GridInlineEditing<M> editing;
private final Class<M> clazzM;
public GenericEditableGrid(Class<M> parametrizedClass, String gridTitle, ListStore<M> listStore, ColumnModel<M> cm) {
super(listStore, cm);
clazzM = parametrizedClass;
// ... then I create my widget
bind();
}
private void bind(){
newItemButton.addSelectHandler(new SelectEvent.SelectHandler() {
#Override
public void onSelect(SelectEvent selectEvent) {
editing.cancelEditing();
// it is the folliwing line which is the problem obviously
M element = GWT.create(clazzM);
getStore().add(0, element);
int index = 0;
editing.startEditing(new Grid.GridCell(getStore().indexOf(element), index));
}
});
}
}
And this is how I use it in my subclasses:
super(InternationalString.class, gridTitle, new ListStore<InternationalString>(isprops.key()), buildColumnModel());
Basically, I would like to know what the problem is exactly with this approach and eventually how I should do to make it well.
Please note that my concern is not just to make it work, but more to do it the right way. As I could just avoid the problem using an abstract method which would handle the GWT.create() method in the daughter classes. But this is not the design I want, it just doesn't look right.
What I don't get also is what's the difference between doing this:
MyClass e = GWT.create(MyClass.class);
and:
Class<MyClass> clazz=MyClass.class;
MyClass e = GWT.create(clazz);
Because as far as I am concerned I think this is basically what I am doing and it looks like the same thing. Isn't it?
There's a well-worded explanation in this forum:
As the error message indicates, only class literals may be passed to the GWT.create method. The reason for this is that all GWT.create calls are basically turned into constructors at compile time, using the deferred binding rules for your module. As a result, all classes must be decided at compile time - your code requires that the at runtime the class is decided. This is too late, and so cannot be compiled.
GWT is not proper java, and so cannot be always treated as java. This is one such example of things that cannot be done in gwt. ...
What is it you are trying to do? Either you are making it far more complicated than it needs to be, or you need to write a generator to do it instead of taking this approach.