RESTEasy, CDI, embedded Jetty, bean validation is ignored - groovy

I've a Groovy project where I use RESTEasy with Weld and deploy to embedded Jetty. What I can't seem to get working is bean validation. RESTEasy documentation says that adding resteasy-validator-provider-11 along with hibernate validator dependencies (hibernate-validator, hibernate-validator-cdi, javax.el-api, javax.el) is enough. But the bean validation is simply ignored by RESTEasy. I curiously also get the following message in the logs:
plugins.validation.ValidatorContextResolver - Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory
Based on the suggestions on [this][1] post, I tried registering Hibernate InjectingConstraintValidatorFactory in META-INF/validation.xml but it depends on a BeanManager being injected and blows up at runtime.
The code can be found here https://github.com/abhijitsarkar/groovy/tree/master/movie-manager/movie-manager-web
A log gist is here: https://gist.github.com/anonymous/8947319
I've tried everything under the sun without any success. Pls help.

To do this without EE, I believe you'll need to fork the existing InjectingConstraintValidatorFactory but instead of using injection of the bean manager, use the CDI 1.1 class CDI to get a reference to the bean manager, e.g. CDI.current().getBeanManager(). http://docs.jboss.org/cdi/api/1.1/javax/enterprise/inject/spi/CDI.html
You do need to be on CDI 1.1 to do this (so Weld 2+, 2.1.1 is current I believe). Here's an example impl, based on: https://github.com/hibernate/hibernate-validator/blob/master/cdi/src/main/java/org/hibernate/validator/internal/cdi/InjectingConstraintValidatorFactory.java
public class InjectingConstraintValidatorFactory implements ConstraintValidatorFactory {
// TODO look for something with better performance (HF)
private final Map<Object, DestructibleBeanInstance<?>> constraintValidatorMap =
Collections.synchronizedMap( new IdentityHashMap<Object, DestructibleBeanInstance<?>>() );
private final BeanManager beanManager;
public InjectingConstraintValidatorFactory() {
this.beanManager = CDI.current().getBeanManager();
Contracts.assertNotNull( this.beanManager, "The BeanManager cannot be null" );
}
#Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
DestructibleBeanInstance<T> destructibleBeanInstance = new DestructibleBeanInstance<T>( beanManager, key );
constraintValidatorMap.put( destructibleBeanInstance.getInstance(), destructibleBeanInstance );
return destructibleBeanInstance.getInstance();
}
#Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
DestructibleBeanInstance<?> destructibleBeanInstance = constraintValidatorMap.remove( instance );
destructibleBeanInstance.destroy();
}
}

I finally fixed this. Turns out, a validation.xml is not really required, resteasy-cdi module does a fine job of registering the BeanManager. What I was missing and not clearly documented anywhere, is that if an annotation is placed on a method, the validation engine just "decides" what should be validated. I placed a #NotNull on a method and it was validating the return type, not the parameters. One can use validationAppliesTo element in some cases but #NotNull doesn't have it. When I moved it from the method to the parameter, it started working.
Now I ran across what I believe is a Weld bug but I'll post that question separately.

Related

Rename WELD request parameter "cid" [duplicate]

This question already has answers here:
Get rid of org.jboss.weld.context.NonexistentConversationException, when a query-string parameter named cid is appended to the URL
(3 answers)
Closed 3 years ago.
I have a project with "Omnifaces 3.3" and "weld.servlet.shaded 3.0.5.Final".
I need to use a request parameter named "cid" in my application, but using it produces the next exception in Weld:
javax.servlet.ServletException: WELD-000321: No conversation found to restore for id 12312312
javax.faces.webapp.FacesServlet.service(FacesServlet.java:683)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
es.ine.sgtic.web.filter.SessionTimeoutFilter.doFilter(SessionTimeoutFilter.java:38)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
I'm trying to rename the parameter that uses Weld internally using the next context-param, but it doesn't work, it keeps using "cid":
servletContext.setInitParameter("WELD_CONTEXT_ID_KEY", "weldCid")
I'm using JSF 2.3 with Spring, so my beans are managed by Spring with the annotation #Component. I've seen other solutions where they Inject #Inject private HttpConversationContext conversationContext; in an application bean, but it isn't available, and Spring doesn't find any implementation of that interface if I try to inject it in a bean.
How can I rename that parameter or get rid of it. I only use WELD in my project because Omnifaces requires it, but I don't really use anything from it.
Thanks.
After many tests, the only thing that worked was the next listener.
#WebListener
public class MyServletContextListener implements ServletContextListener {
#Inject
private HttpConversationContext conversationContext;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.hideConversationScope();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
// Not used
}
private void hideConversationScope() {
this.conversationContext.setParameterName(UUID.randomUUID().toString());
}
}
Here the object "conversationContext" was properly initialized and the renamed worked.

Seed value in Weld CDI custom scope

Coming from a Guice background, I know that it is possible to seed an object value from a scope using.
scope.seed(Key.get(SomeObject.class), someObject);
I suppose one could do this by registering a Bean that gets a value from an AbstractBoundContext, but examples just seeding one value from a Custom Scope seem hard to find. How do I create a custom scope that seeds a value that can be injected elsewhere?
Edit:
I am currently using the following workaround, that can be injected in an interceptor to set the Configuration when entering the scope, and can then be injected through its thread local provider. I am still looking for options that feel less hacky / are more integrated with the scope/scope context system in Weld though.
#Singleton
public class ConfigurationProducer {
private final InheritableThreadLocal<Configuration> threadLocalConfiguration =
new InheritableThreadLocal<>();
#Produces
#ActiveDataSet
public ConfigurationConfiguration() {
return threadLocalConfiguration.get()
}
public void setConfiguration(Configuration configuration) {
threadLocalConfiguration.set(configuration);
}
}
The answer is to register a custom bean with the AfterBeanDiscovery event, like so:
event.addBean()
.createWith(ctx -> commandContext.getCurrentCommandExecution())
.addType(CommandExecution.class)
.addQualifier(Default.Literal.INSTANCE)
.scope(CommandScoped.class)
.beanClass(CommandExtension.class);
There is a quite sophisticated example available at https://github.com/weld/command-context-example

CDI: How to put an existing object into application scope (without writing CDI extension)?

I have an object which I initialized manually (legacy code).
I'd like to put this object to the application context to make it available through CDI.
How do I do that without writing a CDI extension?
Using a producer. Make a bean that #Produces instances of your class.
Do you need something like that?
#ApplicationScoped
public class ApplicationScopedClass {
#Produces
public static ApplicationScopedClass makeAnInstance() {
return new ApplicationScopedClass();
}
}

Using Properties from ResourceBundle in ManagedProperty

I have a JSF Validator that I'm building that has properties in it that I would like to have loaded from a ResourceBundle. However, I'm not quite sure how to work this, as it isn't loading properly. Any ideas on how I can make this work?
I've tried using a #PostContruct to do it, but I'm getting the following error in Eclipse:
Access restriction: The type
PostConstruct is not accessible due to
restriction on required library
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar
So, I'm not too sure what the best way to work this. A sample of what I'm talking about is below...
The validator...
#FacesValidator("usernameValidator")
public class UserNameValidator implements Validator {
#ManagedProperty(value="#{props_userNamePattern}")
private String userNamePattern;
#ManagedProperty(value="#{props_minUserNameLength}")
private int minUserNameLength;
#ManagedProperty(value="#{props_maxUserNameLength}")
private int maxUserNameLength;
public void validate(FacesContext context, UIComponent component, Object
value) throws ValidatorException {
//My validations here...
}
//Setters for the class properties
}
faces-config.xml
<resource-bundle>
<base-name>settings</base-name>
</resource-bundle>
settings.properties
props_userNamePattern = /^[a-z0-9_-]+$/
props_minUserNameLength = 3
props_maxUserNameLength = 30
The #ManagedProperty works on #ManagedBean classes only. The #PostConstruct will also not be the correct solution for your functional requirement. It is intented to be placed on a method which is to be executed when the class has been constructed and all dependency injections are been finished. The error which you're facing is caused by a specific combination of older Eclipse+JRE versions. If upgrading is not an option, you could disable the warning/error by Window > Preferences > Java > Compiler > Errors/Warnings > Deprecated and restricted API > Forbidden reference > Ignore.
As to your functional requirement, unfortunately no annotation which achieves that comes to mind. You could however get it programmatically.
String bundlename = "settings";
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
ResourceBundle bundle = ResourceBundle.getBundle(bundlename, locale);
String usernamePattern = bundle.getString("props_userNamePattern");
// ...
You can do that in the constructor of the validator. When used properly a new instance will be created for every view anyway.
Adding to the correct answer of BalusC; In JSF 2.0/2.1 Validators, Converters, PhaseListeners, etc are a kind of 'second-class' citizen as they are not injection targets.
This also means you can't inject an entity manager or an EJB, which can sometimes be used for validation purposes.
In JSF 2.2 this is supposed to change:
All JSF lifecycle artifacts should be
CDI-aware and support
injection/JSR-299/JSR-330
(PhaseListeners, NavHandlers,
Components, ActionListeners,
everything.)
See: http://jcp.org/en/jsr/detail?id=344
Perhaps seam-faces might help for this situation?
http://docs.jboss.org/seam/3/faces/latest/reference/en-US/html/artifacts.html
http://docs.jboss.org/seam/3/faces/latest/reference/en-US/html/faces.messages.html

Prevent component tree serialization for certain parts of application

Is it possible to explicitly deny JSF from serializing some component trees? At the moment I am passing a non-serializable object to a <h:inputText>:
<h:inputText value="#{nonSerializableBean.nonSerializableClassInstance}" />
What happens after a few clicks is that I get (during view restoration):
javax.faces.FacesException: Unexpected error restoring state for component
with id configurationForm:j_idt292:j_idt302:field. Cause:
java.lang.IllegalStateException: java.lang.InstantiationException:
my.namespace.NonSerializableClass
I think this occurs because JSF cannot restore the nonSerializableClassInstance:
Caused by: java.lang.IllegalStateException: java.lang.InstantiationException: com.foobar.utils.text.Period
at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:110)
at javax.faces.component.ComponentStateHelper.restoreState(ComponentStateHelper.java:292)
at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1444)
at javax.faces.component.UIOutput.restoreState(UIOutput.java:255)
at javax.faces.component.UIInput.restoreState(UIInput.java:1359)
A bonus question: Is it ok not to make backing beans Serializable? Should this then prevent serialization/deserialization of these?
Some background:
We have a bunch of 3rd party classes that we need to provide forms for in JSF. The problem is that we cannot directly use these classes on JSF pages, because they do not implement Serializable interface, and thus will/should fail if JSF runtime decides to serialize/deserialize the page and the component-tree. The classes are "closed" and we are not allowed to modify them.
Running Mojarra 2.0.2.
Javabeans are by spec supposed to implement Serializable. JSF just follows/adheres this spec.
The classes are "closed" and we are not allowed to modify them.
Your best bet is to wrap it as a transient property of a class which implements Serializable and implement the writeObject() and readObject() accordingly.
public class SerializableClass implements Serializable {
private transient NonSerializableClass nonSerializableClass;
public SerializableClass(NonSerializableClass nonSerializableClass) {
this.nonSerializableClass = nonSerializableClass;
}
public NonSerializableClass getNonSerializableClass() {
return nonSerializableClass;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(nonSerializableClass.getProperty1());
oos.writeObject(nonSerializableClass.getProperty2());
// ...
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
nonSerializableClass = new NonSerializableClass();
nonSerializableClass.setProperty1((String) ois.readObject());
nonSerializableClass.setProperty2((String) ois.readObject());
// ...
}
}
Finally use that class instead. You could eventually let it extends NonSerializableClass and then autogenerate delegate methods by a bit decent IDE.
Either way, it's only going to be a lot of opaque and boilerplate code, but since you're not allowed to modify those classes... (I would personally just push that 3rd party stuff to have them their so-called Javabeans to implement Serializable since it are them who's breaking the standards/specs).
I don't know what you expect if the class members (e.g. nonSerializableClassInstance) are not getting serialized.
Of course, you can mark them as transient.
The aim of a managed bean is to hold the application state - you will lose the state if some members are not getting serialized (if the server has the need of doing this).

Resources