Apache Wicket: Injecting dependencies in form vali

2019-07-30 14:28发布

问题:

(This is basically a follow on this question.)

I need to access the DB service layer in one of my form validators (to make sure the email is not already taken when registering a new user).

I tried the following (some input-fields omitted for brevity):

public class RegistrationPage extends WebPage {

    @Inject
    private UserService userService;

    public RegistrationPage() {

        add(new FeedbackPanel("feedback"));

        TextField<String> email = new TextField<String>("email", Model.of(""));

        ...

        email.add(new IValidator<String>() {

            @Override
            public void validate(IValidatable<String> validatable) {

                String email = validatable.getValue();

                if (userService.findUserByEmail(email) != null) {

                    // report error...

                }
            }
        });

        Form<?> form = new Form<Void>("registrationForm") { ... };

        form.add(email);
        add(form);
    }
}

This can unfortunately result in a

java.lang.IllegalStateException: EntityManager is closed

I suspect that the problem is due to the fact that I'm using open-session-in-view and that multiple form-submissions span over several requests. The userService is injected for the first request and (illegally) reused in subsequent requests. (Multiple form-submissions happen if the validation fails and the user attempts to submit the form again.)

My Question

What is the best way to solve this? The same way as I solved the previous, similar problem? It will undoubtedly get messier in this case.

回答1:

There is a bit different lifecycle that you want and that wicket uses.

First think first, understand Wicket component instantion and injection:

  1. Instance the component
  2. Invoke injector - IComponentInstantionListener.onInstantiation(Component component)
  3. Inject annotated field
  4. Use component (render, etc.)
  5. Next request(s) - use the same component with injected fields

What to do? Use a proxy class that is injected into field(s). When the proxy class is invoked it ever uses the current bean.

See SprinComponentInejctor at http://ci.apache.org/projects/wicket/apidocs/6.0.x/org/apache/wicket/spring/injection/annot/SpringComponentInjector.html

see AnnotProxyFieldValueFactory at http://ci.apache.org/projects/wicket/apidocs/6.0.x/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.html

Even you have to write your own implementation or look to Wicket Contrib or Wicket Stuff.