Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing problem: validation errors ignored on redirects. Closes #476 #725

Merged
merged 21 commits into from
Aug 30, 2014

Conversation

renanigt
Copy link
Contributor

@renanigt renanigt commented Aug 2, 2014

In conversation on Issue #476, @lucascs asked me to send this PR to start the bug fix.

Here the gist with the problematic controller as he asked me: Problematic Controller

@renanigt renanigt changed the title Fixing problem: validation ignored on redirects. Closes #476 Fixing problem: validation errors ignored on redirects. Closes #476 Aug 2, 2014
@@ -27,6 +27,7 @@
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;

import org.jboss.weld.exceptions.IllegalStateException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use java.lang.IllegalStateException instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really. Thanks. :-)

@Turini Turini added the bug label Aug 4, 2014
+ "validator.onErrorUse(page()).of(AnyController.class).anyMethod();\n"
+ "or any view that you like.\n"
+ "If you didn't add any validation error, it is possible that a conversion error had happened.");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad indent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. thanks @lucascs . ;-)

@lucascs
Copy link
Member

lucascs commented Aug 5, 2014

What is the problem the controller is causing?

if it's returning a 500 with the message you configured, it's the expected behavior

@renanigt
Copy link
Contributor Author

renanigt commented Aug 5, 2014

The only problem that I saw, is that when using something like:

@Post("/add")
public void add(Usuario usuario) {
    validator.addIf(Strings.isNullOrEmpty(usuario.getLogin()), new SimpleMessage("Login", "Login inválido."));

    result.redirectTo(this).index();
}

The error is only this exception: https://github.com/caelum/vraptor4/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java#L98

But with the approach of this PR and using something like result.use(json()).from ("test").serialize(); instead of result.redirectTo(this).index();, before exception above, I got either this exception:

net.vidageek.mirror.exception.ReflectionProviderException: Could not invoke method add
    net.vidageek.mirror.provider.java.PureJavaMethodReflectionProvider.invoke(PureJavaMethodReflectionProvider.java:45)
    net.vidageek.mirror.invoke.MethodHandlerByMethod.withArgs(MethodHandlerByMethod.java:54)
    br.com.caelum.vraptor.observer.ExecuteMethod.execute(ExecuteMethod.java:87)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:93)
    org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:266)
    org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:253)
    org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:232)
    org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:169)
    org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:165)
    org.jboss.weld.event.ObserverNotifier.notifyObservers(ObserverNotifier.java:119)
    org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:112)
    org.jboss.weld.event.EventImpl.fire(EventImpl.java:83)
    br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:78)
    br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:75)
    br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor$Proxy$_$$_WeldClientProxy.intercept(Unknown Source)
    br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:58)
    br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:83)
    br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:98)
    br.com.caelum.vraptor.interceptor.FlashInterceptor$Proxy$_$$_WeldClientProxy.intercept(Unknown Source)
    br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:58)
    br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:83)
    br.com.caelum.vraptor.core.DefaultInterceptorStack.start(DefaultInterceptorStack.java:93)
    br.com.caelum.vraptor.core.DefaultInterceptorStack$Proxy$_$$_WeldClientProxy.start(Unknown Source)
    br.com.caelum.vraptor.observer.RequestHandlerObserver.handle(RequestHandlerObserver.java:86)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:606)
    org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:93)
    org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:266)
    org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:253)
    org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:232)
    org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:169)
    org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:165)
    org.jboss.weld.event.ObserverNotifier.notifyObservers(ObserverNotifier.java:119)
    org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:112)
    org.jboss.weld.event.EventImpl.fire(EventImpl.java:83)
    br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:119)

@renanigt
Copy link
Contributor Author

renanigt commented Aug 5, 2014

@csokol opened a PR with something like this problem with exception, I don't know if can solves this issue.

See: #728 and #729.

@lucascs
Copy link
Member

lucascs commented Aug 5, 2014

is there any caused by or root cause for this exception?

@renanigt
Copy link
Contributor Author

renanigt commented Aug 5, 2014

is there any caused by or root cause for this exception?

No.

I tested the @csokol's solution, and solved this problem...

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

@lucascs do you think that we need check just for Results.json() and Results.xml() since using Results.http(), request.sendRedirect(...) and result.redirectTo(...).someMethod() we get the correct behavior ? Or we need just check for validator.hasErrors() and throw exception to all cases ?

@lucascs
Copy link
Member

lucascs commented Aug 6, 2014

I'd rather throw the exception as soon as possible.

so for all result.use

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

@lucascs since the PR #729 fix the problem with exception that I cited before, should I need wait the merge and update my branch before another changes or can I going ahead ?

@lucascs
Copy link
Member

lucascs commented Aug 6, 2014

go ahead... write some unit tests for it

maybe you can remove the exception thrown on ExecuteMethodObserver also.

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

If I remove the exception thrown on ExecuteMethodObserver don't will cause conflict with PR #729 since both are changing the same class ?

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

Making some tests, now the problem is because Validator uses Result to make the redirects, forwards...

So, I can't just add this check on method use.

I'll do another tests and take a look about how I can fix the problem, but if do you have some suggestions, I think you. rs

@lucascs
Copy link
Member

lucascs commented Aug 6, 2014

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

Yes, I can. 😃

@lucascs
Copy link
Member

lucascs commented Aug 6, 2014

about the cyclic problem, we can fix it by clearing validation#errors here:
https://github.com/caelum/vraptor4/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/validator/DefaultValidator.java#L144

before returning the viewsFactory

Not sure if I like the solution though... What do you think? @garcia-jj @Turini

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

Maybe a solution for the cyclin problem, if do you agree, I can do it. @lucascs @garcia-jj @Turini

Moving the check for validation erros to use method, I got the error but still with the ReflectionProviderException that is caused here: https://github.com/caelum/vraptor4/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/observer/ExecuteMethod.java#L87

So we still need the PR #729.

@Turini
Copy link
Member

Turini commented Aug 6, 2014

I'm from mobile, so I didn't look at all code. But about cyclic problem you can just
"lazy injected" the bean with Instance<?>. CDI will handle the problem as expected.

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

@Turini sorry if I didn't understand your point and as you said you're from mobile and didn't look at all code.

I think when @lucascs said about cyclic problem is because Validator uses Result to make its redirects, forwards... so if we just check for validator.hasErrors() on result.use to throw exception, we always get the exception since Validator will use Result.

Can we resolve this with Instance<?> ?

Thanks a lot. 😃

@Turini
Copy link
Member

Turini commented Aug 6, 2014

hum, now I see. In this case Instance<Validator> could resolve only if Validator
had @Dependent scope (this is not the case). I think we can use Lucas's solution.

@renanigt
Copy link
Contributor Author

renanigt commented Aug 6, 2014

@garcia-jj do you agree too ?

If so, can I implement it ? @lucascs @Turini @garcia-jj

Thanks. :-)

@renanigt
Copy link
Contributor Author

Done. What do you think ? @lucascs @Turini @garcia-jj

I did some tests with a POC and worked fine.

@renanigt
Copy link
Contributor Author

@Turini
Copy link
Member

Turini commented Aug 29, 2014

This is really simple. Normal scoped beans are "lazy injected". When you inject such bean it will be just a proxy object, the real instance will be called only at the moment when you performed your first action. CDI impl takes care of it, you don't need to use Instance<?> for this specific case. (sorry about the short answer, I'm from mobile right now)

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

@Turini,

This kind of feature in CDI it's interesting but it's weird if you think in
terms of design of the classes. Have you tried to instantiate a class with
circular dependency? I know we can decouple using interfaces but it's still
weird, at least for me. I just think we should avoid it if possible!

As @Turini said, CDI just handles circular reference when at least one of
the beans has normal scope
http://docs.jboss.org/cdi/spec/1.0/html/injectionelresolution.html!

The container is required to support circularities in the bean dependency

graph where at least one bean participating in every circular chain of
dependencies has a normal scope, as defined in Section 6.3, “Normal
scopes and pseudo-scopes”
http://docs.jboss.org/cdi/spec/1.0/html/contexts.html#normalscope. The
container is not required to support circular chains of dependencies where
every bean participating in the chain has a pseudo-scope.

On Fri, Aug 29, 2014 at 6:55 AM, Rodrigo Turini notifications@github.com
wrote:

This is really simple. Normal scoped beans are "lazy injected". When you
inject such bean it will be just a proxy object, the real instance will be
called only at the moment when you performed your first action. CDI impl
takes care of it, you don't need to use Instance<?> for this specific case.
(sorry about the short answer, I'm from mobile right now)


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@Turini
Copy link
Member

Turini commented Aug 29, 2014

I just think we should avoid it if possible!

I agree about avoiding it, but to use Instance<?> will change nothing.
We need a better design for this solution. What do you suggest?

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

Hi @Turini,

Why not put assertAbsenceOfErrors
https://github.com/renanigt/vraptor4/blob/validationIgnoredOnRedirects/vraptor-core/src/main/java/br/com/caelum/vraptor/validator/Messages.java#L121
method inside of Validator or another class? It's a little bit weird having
this method inside of Messages. Maybe I'm missing something, but what do
you think?

On Fri, Aug 29, 2014 at 8:34 AM, Rodrigo Turini notifications@github.com
wrote:

I just think we should avoid it if possible!

I agree about avoiding it, but to use Instance<?> will change nothing.
We need a better design for this solution. What do you suggest?


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@Turini
Copy link
Member

Turini commented Aug 29, 2014

extracting assertAbsenceOfErrors to a new bean can be better, but it won't
avoid the cyclic dependency, it'll just hide it :) makes sense? this is because the
Messages will need the new component that will need the Validator that need
Messages again. What do you think about it @lucascs and @garcia-jj?

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

Turini,

What I mean is that the place of assertAbsenceOfErrors method seems like
it's not in the right class. Which class is invoking the
assertAbsenceOfErrors method?

On Fri, Aug 29, 2014 at 8:59 AM, Rodrigo Turini notifications@github.com
wrote:

extracting assertAbsenceOfErrors to a new bean can be better, but it
won't
avoid the cyclic dependency, it'll just hide it :) makes sense? this is
because the
Messages will need the new component that will need the Validator that
need
Messages again. What do you think about it @lucascs
https://github.com/lucascs and @garcia-jj https://github.com/garcia-jj?


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@renanigt
Copy link
Contributor Author

Thanks for the explanation @Turini and @rponte !

@rponte assertAbsenceOfErrors is invoked by DefaultResult and ExecuteMethod.

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

Hi @renanigt,

As you can see, DefaultResult and ExecuteMethod use Messages only to
call assertAbsenceOfErrors
method, when they could use Validator instead. This way we could put
assertAbsenceOfErrors method inside Validator and avoid circular dependency
at all.

What do you think?

On Fri, Aug 29, 2014 at 9:09 AM, Renan Montenegro notifications@github.com
wrote:

Thanks for the explanation @Turini https://github.com/Turini and @rponte
https://github.com/rponte !

@rponte https://github.com/rponte assertAbsenceOfErrors is invoked by
DefaultResult and ExecuteMethod.


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@renanigt
Copy link
Contributor Author

@rponte makes sense for me. I agree with you.

What do tou think @lucascs @Turini @garcia-jj ?

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

Humm.. I see now, Validator uses Result too so we end up with another
circular dependency. I think we should extract a new class just to verify
the absence of errors and use it wherever it's needed.

On Fri, Aug 29, 2014 at 9:14 AM, Rafael Ponte rponte@gmail.com wrote:

Hi @renan,

As you can see, DefaultResult and ExecuteMethod use Messages only to call assertAbsenceOfErrors
method, when they could use Validator instead. This way we could put
assertAbsenceOfErrors method inside Validator and avoid circular
dependency at all.

What do you think?

On Fri, Aug 29, 2014 at 9:09 AM, Renan Montenegro <
notifications@github.com> wrote:

Thanks for the explanation @Turini https://github.com/Turini and
@rponte https://github.com/rponte !

@rponte https://github.com/rponte assertAbsenceOfErrors is invoked by
DefaultResult and ExecuteMethod.


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@renanigt
Copy link
Contributor Author

@rponte True, I didn't see that.

@rponte
Copy link
Contributor

rponte commented Aug 29, 2014

Well, dealing with circular dependency it's not so easy as we thought :-)

On Fri, Aug 29, 2014 at 9:19 AM, Renan Montenegro notifications@github.com
wrote:

@rponte https://github.com/rponte True, I didn't see that.


Reply to this email directly or view it on GitHub
#725 (comment).

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

@renanigt
Copy link
Contributor Author

I think the best solution is extract the assertAbsenceOfErrors method to a new bean.

@Turini if we extract it to a new bean, Messages don't will need the new component since the assertAbsenceOfErrors method is invoked just by DefaultResult and ExecuteMethod.

@renan
Copy link

renan commented Aug 29, 2014

Wrong @renan?

@renanigt
Copy link
Contributor Author

Wrong @renan?

I think so. 😃

} catch (ValidationException e) {
log.debug("Some validation errors occured: {}", e.getErrors());
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need validator here.

you already have the errors (getErrors()), just use it.

and remove validator dependency.

no more cyclic dependency ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can change this whole if on line 123 to:

log.debug("Some validation errors occured: {}", getErrors());

slf4j already does the if internally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucascs what about validator.onErrorUse(nothing()); ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True @lucascs, now I see your point. 😃

Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's from the time we didn't have validator.getErrors() method, so we had to catch the exception to be able to get the errors. VRaptor 3 inheritance ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @lucascs. 😃

@renanigt
Copy link
Contributor Author

Done. What do you think ? @lucascs @Turini @garcia-jj @rponte

@@ -238,7 +248,7 @@ public void shouldDelegateToStatusOnPermanentlyRedirectToControllerInstance() th
result.permanentlyRedirectTo(new RandomController());

verify(status).movedPermanentlyTo(RandomController.class);

verify(messages).assertAbsenceOfErrors();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave this verify only for the method which is checking this behavior. No need to repeat it on all.

@renanigt
Copy link
Contributor Author

Done @lucascs !

@renanigt
Copy link
Contributor Author

For @lucascs this issue can be merged.

What do you think ? @Turini @garcia-jj

@Turini
Copy link
Member

Turini commented Aug 30, 2014

sounds nice, thanks

Turini added a commit that referenced this pull request Aug 30, 2014
Fixing problem: validation errors ignored on redirects. Closes #476
@Turini Turini merged commit dbe7799 into caelum:master Aug 30, 2014
@renanigt renanigt deleted the validationIgnoredOnRedirects branch September 2, 2014 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants