I have following controller:
public static Result overview() {
class Earning {
public int ammount;
public String description;
}
Earning[] earnings = new Earning[5];
earnings[0].ammount = 5;
return ok(overview.render(earnings));
}
I didn't created corresponding object in array as a result in Java I should get: java.lang.NullPointerException
But instead of showing this error Play framework crashes.
Any ideas how not to crash the framework and see the error in first place?
Add:
earnings[0] = new Earning();
before:
earnings[0].ammount = 5;
This way, earnings[0] will hold an Earning object and you would be able to access its ammount field.
Don't declare the Earning class inside the overview method.
It's creating a visibility issue because this class should only be accessible in the method body, but your "leaking" it by passing it to a view.
Related
I need to unit test a method, and I would like mock the behavior so that I can test the necessary part of the code in the method.
For this I would like access the object returned by a private method inside the method I am trying to test. I created a sample code to give a basic idea of what I am trying to achieve.
Main.class
Class Main {
public String getUserName(String userId) {
User user = null;
user = getUser(userId);
if(user.getName().equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
private User getUser(String userId) {
// find the user details in database
String name = ""; // Get from db
String address = ""; // Get from db
return new User(name, address);
}
}
Test Class
#Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = new Main();
// I need to access the user object returned by getUser(userId)
// and spy it, so that when user.getName() is called it returns Stack
main.getUserName("124");
}
There are only two ways to access private:
using reflection
extend the scope
maybe waiting for Java 9 to use new scope mechanisms?
I would change the scope modifier from private to package scope. Using reflection is not stable for refactoring. It doesn't matter if you use helpers like PowerMock. They only reduce the boiler-plate code around reflection.
But the most important point is you should NOT test too deep in whitbox tests. This can make the test setup explode. Try to slice your code into smaller pieces.
The only information the method "getUserName" needs from the User-object is the name. It will validate the name and either throw an exception or return it. So it should not be necessary to introduce a User-object in the test.
So my suggestion is you should extract the code retreiving the name from the User-object into a separate method and make this method package scope. Now there is no need to mock a User-Object just the Main-Object. But the method has its minimal information available to work properly.
class Main {
public String getUserName(String userId) {
String username = getUserNameFromInternal(userId);
if (userName.equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
String getUserNameFromInternal(String userId) {
User user = getUser(userId);
return user.getName();
}
...
}
The test:
#Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = Mockito.mock(new Main());
Mockito.when(main.getUserNameInternal("124")).thenReturn("Stack");
main.getUserName("124");
}
Your problem that call to new within your private method.
And the answer is not to turn to PowerMock; or to change the visibility of that method.
The reasonable answer is to "extract" that dependency on "something that gives me a User object" into its own class; and provide an instance of that class to your "Main" class. Because then you are able to simply mock that "factory" object; and have it do whatever you want it to do.
Meaning: your current code is simply hard-to-test. Instead of working around the problems that are caused by this, you invest time in learning how to write easy-to-test code; for example by watching these videos as a starting point.
Given your latest comment: when you are dealing with legacy code, then you are really looking towards using PowerMockito. The key part to understand: you don't "mock" that private method; you rather look into mocking the call to new User() instead; as outlined here.
You can use a PowerMock's mockPrivate but I don't recommend it.
If you has such a problem it usually mean that your design is bad.
Why not making the method protected?
I'm going mad with an error non error on my web-app Flex 3.6 based (using BlazeDS). I try to describe my issue: I have a java class:
public class User {...}
and the binding one in .as:
[Bindable]
[RemoteClass(alias="it.dto.User")]
public class User {...}
I also have a DataManager.as to do the Async call like this:
public function getUser():void {
var token:AsyncToken = _service.getUser();
token.addResponder(new AsyncResponder(userOnResult,userOnFault));
}
private function userOnFault(event:FaultEvent,token:Object):void {
var _fail:String = "Error";
}
private function socOnResult(event:ResultEvent,token:Object):void {
_resUser = event.result as ArrayCollection;
dispatchEvent(new MyEvent("USER_EVENT",_resUser));
}
Now I implemented the following code in two different .as file (different package), which refers to two different .mxml:
var data:DataManager = new DataManager;
....
data.addEventListener("USER_EVENT",userResult);
....
data.getUser();
....
private function userResult(dataEvent:MyEvent):void {
var user:ArrayCollection = new ArrayCollection;
user = dataEvent.result as ArrayCollection;
for (var i:int = 0;i<user.length; i++) {
var u:User = new User;
u = (User)(user.getItemAt(i));
}
_dm.removeEventListener("USER_EVENT",userResult);
}
The drama is that in the first .as it works perfectly, and in the second .as give me a Error of coercion failed. In the second file seems how it can't recognize the User class.
Do you have any idea?? I'm going mad!!
Thank you
#Stacktrace error:
TypeError: Error #1034: Type Coercion failed: cannot convert appcode.dto::SocietaDTO#b4dbfc1 to appcode.dto.SocietaDTO.
at modules::ReportIspezioni/onSocResult()[D:\workspace\maga\aga\flex_src\modules\ReportIspezioni_src.as:80]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at appcode.dao::DataManager/socOnResult()[D:\workspace\maga\aga\flex_src\appcode\dao\DataManager.as:180]
at mx.rpc::AsyncResponder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncResponder.as:82]
at mx.rpc::AsyncToken/http://www.adobe.com/2006/flex/mx/internal::applyResult()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncToken.as:199]
at mx.rpc.events::ResultEvent/http://www.adobe.com/2006/flex/mx/internal::callTokenResponders()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\events\ResultEvent.as:172]
at mx.rpc::AbstractOperation/http://www.adobe.com/2006/flex/mx/internal::dispatchRpcEvent()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AbstractOperation.as:199]
at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::resultHandler()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AbstractInvoker.as:263]
at mx.rpc::Responder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\Responder.as:46]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:524]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.x\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]
Obviusly the User class written above is just for example, to understand the code logic. The real class is a DTO calls SocietaDTO.
N.B: The code works perfectly in another module of my project.. I don't understand why here it doesn't work.
Thanks a lot
I never save browser cache when developing.. Anyway I solve the Issue by adding this:
registerClassAlias("it.mec.dto.SocietaDTO", SocietaDTO);
In the class were exception launch.
Thanks anyway
I have a class called Sell which has a SimpleObjectProperty.
In the POJO, the getters and setters are the following:
private ObjectProperty<LocalDateTime> sellDate;
....
public LocalDateTime getSellDate() {
return sellDate.get();
}
public void setSellDate(LocalDateTime value) {
sellDate.set(value);
}
When creating a new instance of the Sell class, I use the method setSellDate():
....
Sell sell = new Sell();
//another gets and sets...
sell.setSellDate(LocalDateTime.now());
This line of code is giving me a NullPointerException.
What am I doing wrong?
Since sell clearly isn't null, sellDate must be the reference that is null. You show where you declare it with
private ObjectProperty<LocalDateTime> sellDate;
but you don't show any code that initializes it. You need something like
sellDate = new SimpleObjectProperty<>();
in the constructor.
I am new to Java and I have failed to find anything about this case.
I am basically trying to pass this array called vakken to a new class called Vak,
Vak expects to receive a String and a int.
Vak[] vakken = new Vak[1];
vakken[0] = new Vak("Test",3);
Vak vak = new Vak(vakken[0]);
Whenever I try the code above I get this error.
Exception in thread "main" java.lang.UnsupportedOperationException: Not supported yet.
at ectsmonitor2.Vak.<init>(Vak.java:24)
at ectsmonitor2.ECTSmonitor2.main(ECTSmonitor2.java:27)
Java Result: 1
Vak.class
public class Vak {
public String naam;
public int teVerdienenEcts;
public Vak(String vakNaam, int vakTeVerdienenEcts){
naam = vakNaam;
teVerdienenEcts = vakTeVerdienenEcts;
}
}
You haven't actually coded your constructor that takes a Vak yet, you made it throw UnsupportedOperationException. Put some code in the constructor e.g.
public Vak(Vak v) {
this(v.naam, v.teVerdienenEcts);
}
This line wont work for sure
Vak vak = new Vak(vakken[0]);//IDE will display error message here
Because you have no such constructor for this.
Create a new constructor that takes an object of its own type.
Similar to this:
public Vak(Vak anObject){
//do stuffs here
}
These type of constructors are called copy constructors
And generally you won't want your attributes to be public. Make them private.
How can I get the name of a method just like I can get the name of a class?
(RandomClass.class.getName())
Hardcoding won't work because the obfuscator destroys it.
Reason:
I'm injecting methods like this:
MethodNode getLocalPlayer = GetterAdapter.insert(false, true, "getLocalPlayer", "Lvanquish/accessors/Player;", "client", "yD", "LQZ;");
classNode.methods.add(getLocalPlayer);
//class client implements my interface which contains the method getLocalPlayer
public interface Client {
public int[] getPlayerIndices();
public Player getLocalPlayer();
public Player[] getPlayers();
public int getBaseX();
public int getBaseY();
public int getCameraX();
public int getCameraY();
}
//when I obfuscate my files getLocalPlayer get's a name like a2
//when you look above you see that the method name was hard code and so
// will it create an error
Declared method wont work here, because I don't know the method name and there are like 4 vars of the same type.
Would this work or would it be a mess?
#DataMap.varDetails(name = "getPlayerIndices")
public int[] getPlayerIndices();
you can try this:
Thread.currentThread().getStackTrace();
it show you the stack of your calling method in current thread.
Best of luck :)
You would need each of the methods you want to refer to reflectively do something like this:
static String baseXName;
public int getBaseX() {
if (baseXName == null)
baseXName = detectMyName();
... the actual code of the method ...
}
and detectMyName() would, as #eran suggests in the first comment to your question, instantiate an Exception and retrieve the actual runtime name of the calling method from its stacktrace. You can avoid a tiny bit of overhead by obtaining the stacktrace without instantiating exception if you call Thread.currentThread().getStackTrace().