Clientside error (Cannot call method 'nullMethod' of null arguments: nullMethod) - facebook

My App engine/ GWT project is spitting out a nasty little pile of stack trace whenever it attempts to return from my login method. I am using GAE version 1.5.0 and GWT version 2.3.0 .
It's a facebook app, so what I've got is this:
The player navigates to the app page.
They click a button, and are redirected to the OAuth authentication page
They are then redirected back to the app, with the authentication token in the query string
I break the query string apart to get the UID, and then use that as the primary key for my Player entity (RPC to app engine backend)
I retrieve the Player entity instance from the datastore, and turn it into a serializable type to return to the client
Epic fail.
When I spit out the exception in a JSAlert, I get a big nasty pile of stack trace (I already was thoughtful enough to compile using "pretty" instead of "obfuscated").
My login function looks like this:
#Override
public ClientPlayer login(String uid) {
PersistenceManager pm=PMF.get().getPersistenceManager();
log.warning(Player.class.getName());
log.warning(uid);
Key k=KeyFactory.createKey(Player.class.getSimpleName(), uid);
Player p;
List<List<Integer>> stats;
try{
p=pm.getObjectById(Player.class, k);
} catch (JDOObjectNotFoundException e){
p=new Player(uid);
p.setKey(k);
pm.makePersistent(p);
} finally {
pm.close();
}
stats=p.getStats();
return new ClientPlayer(p.getUID(),p.getPerm(), p.getDecks(),stats.get(0), stats.get(1), stats.get(2));
}
Unfortunately, due to NDA, I can't link to the app, but here's the output:
Failure to log in because of:
com.google.gwt.core.client.JavaScriptException: (TypeError): Cannot call method 'nullMethod' of null
arguments: nullMethod,
type: non_object_property_call
stack: TypeError: Cannot call method 'nullMethod' of null
at Object.ClientPlayer_1 (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:993:89)
at Object.ClientPlayer_0 (http://*com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:984:18)
at Array.instantiate_1 [as 0] (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:1031:10)
at $instantiate_0 (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:10660:34)
at $instantiate (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:1948:10)
at $readObject (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:10148:95)
at Object.read_8 [as read] (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:10608:10)
at $onResponseReceived (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:10352:247)
at $fireOnResponseReceived (http://*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:5002:5)
at Object.onReadyStateChange (http:/*.com/com.MES.Tap2/A37A2E2E9A65DB1BAAE2BFA42572F7F8.cache.html:5222:5)

The issue was in the use of the IsSerializable interface, or rather my poor understanding of it.
When you create an IsSerialiazable object, it requires a no-argument constructor. I was passing null values from that constructor to the main constructor, so when methods were called on them, null pointer exceptions occurred. This was dumb of me, but hey, it was a learning experience.
In my particular case, it went a little like this...
public class ClientObject implements IsSerializable {
private Object field1;
private Object field2;
private String field3;
public ClientObject(){
this(null, null);
}
public ClientObject(Object arg1, Object arg2){
field1=arg1;
field2=arg2;
field3=arg1.toString()+arg2.toString();
//Error on above line, though not obviously mentioned in the message
}
}
What should have been done was...
public ClientObject(){
this(new Object(), new Object());
}
Hope this helps someone.

Related

Redirect if request authorization is failed in Laravel 5.5

I am trying to redirect request if authorization is failed for it. I have following code:
class ValidateRequest extends Request{
public function authorize(){
// some logic here...
return false;
}
public function rules(){ /* ... */}
public function failedAuthorization() {
return redirect('safepage');
}
}
By default I am redirected to the 403 error page, but I would like to specify some specific route. I noticed that method failedAuthorization() is run, but redirect() method does not work...
Previously this code worked well with Laravel 5.1 but I used forbiddenResponse() method to redirect wrong request. How can I fix it with new LTS version?
Looks like it is impossible to redirect() directly from the custom ValidateRequest class. The only solution that I found is create custom exception and than handle it in the Handler class. So, now it works with following code:
Update: The method redirectTo() was updated to make solution work on Laravel 6.x and higher
app/Requests/ValidateRequest.php
class ValidateRequest extends Request{
public function authorize(){
// some logic here...
return false;
}
public function rules(){
return [];
}
public function failedAuthorization() {
$exception = new NotAuthorizedException('This action is unauthorized.', 403);
throw $exception->redirectTo("safepage");
}
}
app/Exceptions/NotAuthorizedException.php
<?php
namespace App\Exceptions;
use Exception;
class NotAuthorizedException extends Exception
{
protected $route;
public function redirectTo($route) {
$this->route = $route;
abort(Redirect::to($route));
}
public function route() {
return $this->route;
}
}
and app/Exceptions/Handler.php
...
public function render($request, Exception $exception){
...
if($exception instanceof NotAuthorizedException){
return redirect($exception->route());
}
...
}
So, it works, but much more slower than I expected... Simple measuring shows that handling and redirecting take 2.1 s, but with Laravel 5.1 the same action (and the same code) takes only 0.3 s
Adding NotAuthorizedException::class to the $dontReport property does not help at all...
Update
It runs much more faster with php 7.2, it takes 0.7 s
If you are revisiting this thread because in 2021 you are looking to redirect after failed authorization here's what you can do:
You cannot redirect from the failedAuthorization() method because it is expected to throw an exception (check the method in the base FormRequest class that you extend), the side effect of changing the return type is the $request hitting the controller instead of being handled on FormRequest authorization level.
You do not need to create a custom exception class, neither meddle with the Laravel core files like editing the render() of app/Exceptions/Handler.php, which will pick up the exception you threw and by default render the bland 403 page.
All you need to do is throw new HttpResponseException()
In the Laravel reference API we can see its job is to "Create a new HTTP response exception instance." and that is exactly what we want, right?
So we need to pass this Exception a $response. We can pass a redirect or JSON response!
Redirecting:
protected function failedAuthorization()
{
throw new HttpResponseException(response()->redirectToRoute('postOverview')
->with(['error' => 'This action is not authorized!']));
}
So we are creating a new instance of the HttpResponseException and we use the response() helper, which has this super helpful redirectToRoute('routeName') method, which we can further chain with the well known with() method and pass an error message to display on the front-end.
JSON:
Inspired by this topic
throw new HttpResponseException(response()->json(['error' => 'Unauthorized action!'], 403));
Thats'it.
You don't have to make ANY checks for validation or authorization in your controller, everything is done in the background before it hits the controller. You can test this by putting a dd('reached controller'); at the top of your controller method and it shouln't get trigered.
This way you keep your controller thin and separate concerns :)
Sidenote:
forbiddenResponse() has been replaced after lara 5.4 with failedAuthorization()
You can do through a middleware/policy i think. I don't know if you can do it from the validation.
You can override the function from FormRequest like this below:
/**
* Handle a failed authorization attempt.
*
* #return void
*
* #throws \Illuminate\Auth\Access\AuthorizationException
*/
protected function failedAuthorization()
{
throw new AuthorizationException('This action is unauthorized.');
}
And redirect where you want.

GWT requestfactory: How to catch the exception i thrown in Locator at server side?

At client side:
factory.find(proxyId).fire(new Receiver<P>()
{
#Override
public void onSuccess( P response )
{
proxy = response;
...
}
#Override
public void onFailure( com.google.web.bindery.requestfactory.shared.ServerFailure error )
{
Window.alert( error.getMessage() );
}
}
at server side i use an Locator like below:
public class myLocator extends Locator<T, String>
{
#Injector LocatorHook hook;
#Override
public T find( Class<? extends T> clazz, String id )
{
T result = ...;
hook.run( result );
return result;
}
....
}
The hook.run() method may throwRunTimeException("validation exception") there, i expect to catch the
exception at client side in onFailure(), however, i did catch the exception, but the message is "Internal Server Error",
not the exception i thrown in hook.run():"validation exception".
Any ideas to let client catch the exception i throw at server side?
Updation:
As Thomas said it's weird that validating objects that come fresh from data store, but i encounter a
situation that i don't know how to use service method:
At client i get EntityProxyId object, through the factory.find( proxyId ).fire(...) i can get the entity
from datastore, but the entity may not suitable for the user to access, in this situation i need to check it at server side, but i can't find a suitable place to do the
validation, Any ideas about this?
RequestFactory doesn't expect exceptions to be thrown by locators. Exceptions should only be thrown by service methods, and will be directed to the appropriate Receiver on the client-side (the one attached to the service method that threw).
Outside service methods, the only exceptions that gets routed to the client are ReportableExceptions, that can only be thrown from a ServiceLocatorDecorator's report() methods. That means you could hook your own ServiceLocatorDecorator that catches exceptions from your locators and report()s them.
That said, validating objects that come fresh from your data store seems weird. You might want to provide a ServiceLocatorDecorator that overrides validate() (that'll validate the objects after the changes coming from the client have been applied). The errors will go back to the client in the Receiver's onConstraintViolations, and the RequestContext will be unfrozen so you can further edit your proxies and fire() again.

GWT JSNI method call failing, but there are no errors

I'm trying to implement Mozilla's Persona in a GWT App. Here's part of the code from a dummy app I set up to test it:
public class OpenId implements EntryPoint {
private native void callWatch(String email)
/*-{
$wnd.navigator.id.watch({
loggedInUser: email,
onlogin: function(assertion){
$wnd.alert("Calling method");
this.#com.gallup.openid.client.OpenId::processLogin(Ljava/lang/String;)(assertion);
$wnd.alert("Called Java Method");
},
onlogout: function(){alert("Logged Out!");}
});
}-*/;
private void processLogin(String assertion){
Window.alert("Logged in!");
personaStatus.setText("Log In Complete.");
}
}
When I call the callWatch method, only the "Calling method" alert box shows up. Neither of the other ones are ever called. So for some reason the code appears to be stopping at the JSNI call right below the first alert. But there are no errors in Dev Mode.
I don't understand why the processLogin method doesn't get called.
I thought I followed Google's Documentation correctly.
I did try writing
this.#com.gallup.openid.client.OpenId::processLogin(Ljava/lang/String;)(assertion);
as OpenID.#... and instance.#... due to this post.
I'm not sure what else to try.
The variable this points to the function that immediately surrounds it, which is in this case your onlogin JavaScript function. You need to use a temporary that variable (a typical JavaScript idiom, by the way)
private native void callWatch(String email)
/*-{
var that = this;
...
onlogin: function(assertion){
that.#com...
And then, ideally use $entry(...), so you will see error messages, if you have registered an UncaughtExceptionHandler.
See also: https://stackoverflow.com/a/5235580/291741

NullPointerException when using GWT's AutoBean deserialization with HashMap

I have some problem with the Google's AutoBean serialization and deserialization.
I have an AutoBean that contains primitive types and Maps as well. I can serialize and deserialize the primitive types without any problem, but when i try to read the deserialized Map, i get NullPointerException.
Have you ever met with a similar problem before? There is a JUnit test that representes my problem. The first two asserts are passes, but the third fails.
public class AutoBeanTest {
#Test
public void test() throws Exception {
MyFactory myFactory = AutoBeanFactorySource.create(MyFactory.class);
Options options = myFactory.options().as();
options.setMyInt(5);
HashMap<Double, Boolean> map = newHashMap();
map.put(8.0, true);
map.put(9.1, false);
options.setMyMap(map);
Options deserialized = AutoBeanCodex.decode(myFactory, Options.class, AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(options)).getPayload()).as();
assertEquals(deserialized.getMyInt(),5);
assertTrue(options.getMyMap().containsKey(8d));
assertTrue(deserialized.getMyMap().containsKey(8d));
}
public interface MyFactory extends AutoBeanFactory {
AutoBean<Options> options();
}
public interface Options {
public int getMyInt();
void setMyInt(int myInt);
Map<Double, Boolean> getMyMap();
void setMyMap(Map<Double, Boolean> myMap);
}
}
I've been playing around with the AutoBean functionality a while ago. I think it is still kind a buggy. I'm quite sure the exceptions is caused by a bug in the AutoBean code, not in your code.
If you run the above sample code in a debugger and check the generated JSON, things look fine. You can even call deserialized.getMyMap().size() and get the correct value, but once you want to access the content errors occur.
There is a workaround, just use Map<String, String> instead of Double or Boolean and it works...
Ackchyually... Autobeans is doing it correctly as in JSON only strings are allowed as keys. But of course the error message should be more helpful.

How to make JPA EntityListeners validate the existence of an interface

I am working in J2EE 5 using JPA, I have a working solution but I'm looking to clean up the structure.
I am using EntityListeners on some of the JPA objects I am persisting, the listeners are fairly generic but depend on the beans implementing an interface, this works great if you remember to add the interface.
I have not been able to determine a way to tie the EntityListener and the Interface together so that I would get an exception that lead in the right direction, or even better a compile time error.
#Entity
#EntityListener({CreateByListener.class})
public class Note implements CreatorInterface{
private String message;....
private String creator;
....
}
public interface CreatorInterface{
public void setCreator(String creator);
}
public class CreateByListener {
#PrePersist
public void dataPersist(CreatorInterface data){
SUser user = LoginModule.getUser();
data.setCreator(user.getName());
}
}
This functions exactly the way I want it to, except when a new class is created and it uses the CreateByListener but does not implement the CreatorInterface.
When this happens a class cast exception is thrown somewhere deep from within the JPA engine and only if I happen to remember this symptom can I figure out what went wrong.
I have not been able to figure a way to require the interface or test for the presence of the interface before the listener would be fired.
Any ideas would be appreciated.
#PrePersist
public void dataPersist(Object data){
if (!(data instanceof CreatorInterface)) {
throw new IllegalArgumentException("The class "
+ data.getClass()
+ " should implement CreatorInterface");
}
CreatorInterface creatorInterface = (CreatorInterface) data;
SUser user = LoginModule.getUser();
creatorInterface.setCreator(user.getName());
}
This does basically the same thing as what you're doing, but at least you'll have a more readable error message indicating what's wrong, instead of the ClassCastException.