Specifying JPA entity listeners separately being independent of its associated entity - jpa

Entity listeners are commonly placed over respective entity classes such as,
#Entity
#EntityListeners(EntityListener.class)
public class Entity implements Serializable {
//...
}
Applications may use one or more class libraries for sharing common functionalities across different projects/modules. In addition to the EE module, class libraries basically also require entities to be present on the compile-time class-path as a dependency i.e entities are present in both the places namely a class library and an EE module in an enterprise application. As such, the class EntityListener in the given example needs to be present on the compile-time class-path of a class library (it cannot only be added to the EE module).
If entity listeners were not to be tightly-coupled with respective entities and be specified separately then, there would be no need to add this dependency (listeners) to a class library i.e. entity listeners would then be present only in the EE project where EJBs are perfectly eligible for injection using #Inject.
Is there any possibility to separate this annotation #EntityListeners(EntityListener.class) from its associated entity so that it can be declared separately in a separate place? There should not be need to tightly couple this annotation with its respective entity.
Using GlassFish 4.1 having EclipseLink 2.6.0 (JPA 2.1).
This is required as there is a problem injecting EJBs into such entity listeners available in class libraries using the CDI specific artifact #Inject. EJBs could otherwise be injected by using #Inject into listeners, if the listeners were present in the EE project (module) only (but not in a class library).

Yes, you can define the default entity listener with xml.

One way to take the annotation #EntityListeners away from an entity is using both XML and annotation approaches together. Mixing and matching the XML descriptor and metadata annotations is perfectly valid and documented.
In order to override that annotation, one will have to register entity listeners in a file called orm.xml[1] as follows.
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm orm_2_1.xsd">
<entity class="com.example.entity.Entity">
<entity-listeners>
<entity-listener class="com.example.entity.listeners.EntityListener"/>
</entity-listeners>
</entity>
<!--Other listeners-->
</entity-mappings>
The corresponding listener class may then be left untouched with annotations as follows.
public class EntityListener {
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Entity entity) {
// Do something with the entity.
}
}
Those callbacks may vary depending upon the functional requirement.
One may, if necessary, also define callbacks as XML elements avoiding callback annotations in the listener class such as,
<entity class="com.example.entity.Entity">
<entity-listeners>
<entity-listener class="com.example.entity.listeners.EntityListener">
<post-persist method-name="onChange"/>
<post-update method-name="onChange"/>
<post-remove method-name="onChange"/>
</entity-listener>
</entity-listeners>
</entity>
Those three annotations namely #PostPersist, #PostUpdate and #PostRemove in the listener class are now not required, since they are registered in the XML descriptor.
[1] IDEs like NetBeans do not seem to have wizard support for generating the orm.xml file. In NetBeans projects, one will need to create an XML file manually under src/conf (or any other custom configured location) so that the application builder can place that file under META-INF/orm.xml while building/deploying the application.

Related

How to register custom Querydsl EntityPathResolver with Spring Data MongoRepositoryFactory?

I am using the Querydsl extension (QueryDslPredicateExecutor) to my CrudRepository.
To reliably exclude the generated Q classes from my test coverage measurements, they are generated into a dedicated querydsl subpackage of the respective domain classes (annotation processor option -Aquerydsl.packageSuffix=.querydsl).
Alas, this causes a ClassNotFoundException at application start up:
java.lang.IllegalArgumentException: Did not find a query class org.example.QDomain for domain class org.example.Domain!
at org.springframework.data.querydsl.SimpleEntityPathResolver.createPath(SimpleEntityPathResolver.java:63)
at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.<init>(QueryDslMongoRepository.java:85)
at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.<init>(QueryDslMongoRepository.java:67)
…
Caused by: java.lang.ClassNotFoundException: org.example.QDomain
…
I have already located the EntityPathResolver interface that supposedly would allow me to plug in my own domain class to Q class mapping that inserts the .querydsl package suffix, but I haven’t found a way to configure Spring Data’s MongoRepositoryFactory to pick my own EntityPathResolver.
Is this possible?
Currently, the only way is to create your own variant of the MongoRepositoryFactory because the instance of the EntityPathResolver is hard-wired into it.

what is a jaxb provider, jaxb handler, and contextResolvers?

1) What is a JaxB provider, and is it the same as a ContextResolver?
2) What is a jaxb handler?
I'm very lost in these terminologies. Please reply in simple to understand words.
Here it is from the book:
JAXB JAX-RS Handlers
The JAX-RS specification requires implementations to automatically support the marshalling and unmarshalling of classes that are annotated with #XmlRootElement or #XmlType as well as objects wrapped inside javax.xml.bind.JAXBElement instances. Here’s an example that interacts using the Customer class defined earlier:
#Path("/customers")
public class CustomerResource {
#GET
#Path("{id}")
#Produces("application/xml")
public Customer getCustomer(#PathParam("id") int id) {
Customer cust = findCustomer(id);
return cust;
}
#POST
#Consumes("application/xml")
public void createCustomer(Customer cust) {
...
}
}
As you can see, once you’ve applied JAXB annotations to your Java classes, it is very easy to exchange XML documents between your client and web services. The built-in JAXB handlers will handle any JAXB-annotated class for the application/xml, text/xml, or application/*+xml media types. By default, they will also manage the creation and initialization of JAXBContext instances. Because the creation of JAXBContext instances can be expensive, JAX-RS implementations usually cache them after they are first initialized.
Managing your own JAXBContexts with ContextResolvers
If you are already familiar with JAXB, you’ll know that many times you need to configure your JAXBContext instances a certain way to get the output you desire. The JAX-RS built-in JAXB provider allows you to plug in your own JAXBContext instances. The way it works is that you have to implement a factory-like interface called javax.ws.rs.ext.ContextResolver to override the default JAXBContext creation:
public interface ContextResolver<T> {
T getContext(Class<?> type);
}
ContextResolvers are pluggable factories that create objects of a specific type, for a certain Java type, and for a specific media type. To plug in your own JAXBContext, you will have to implement this interface. Here’s an example of creating a specific JAXBContext for our Customer class:
#Provider
#Produces("application/xml")
public class CustomerResolver
implements ContextResolver<JAXBContext> {
private JAXBContext ctx;
public CustomerResolver() {
this.ctx = ...; // initialize it the way you want
}
public JAXBContext getContext(Class<?> type) {
if (type.equals(Customer.class)) {
return ctx;
} else {
return null;
}
}
}
JAXB Provider
A JAXB provider is an implementation of the Java Architecture for XML Binding (JSR-222) specification. This specification was created through the Java Community Process. It was originally lead by Sun Microsystems, but is now lead by Oracle. The expert group had members from several object-to-XML technologies (XMLBeans, EMF, TopLink OX, etc) as well as several individuals. A JAXB implementation is required to pass the Test Compatibility Kit (TCK). Below are links to a couple of JAXB providers:
https://jaxb.java.net/
http://www.eclipse.org/eclipselink/moxy.php
ContextResolver
JAXB is the default object-to-XML provider in JAX-RS. By default it will create a JAXBContext based on the parameter/return type of the JAX-RS annotated method (i.e. annotated with #GET). Then it will pull in all referenced classes to produce metadata as well. Sometimes this doesn't produce all the required metadata and you need to provide the JAXBContext yourself. This can be done with a ContextResolver.
JAXB Handler
I'm not familiar with this term.
JAXB is the acronym for "Java Architecture for XML Binding", a specification defining ways to convert between XML documents and Java object trees, originally created by Sun Microsystems. The valid spec, version 2.0, was completed in 2006.
An implementation according to the JAXB specification is a JAXB provider.
The specification contains some hints, what a plausible implementation might contain. For instance: "The JAXBContext class is the entry point for a Java application into the
JAXB framework." It maintains information about the classes to expect during (un)marshalling. It is created either from one or more packages or from a list of classes. (The process of context resolution may follow hints in the annotation.)
The term "JAXB handler" (as it is used in the quoted text) refers to the code associated with a JAXBContext class that investigates a Java class, introspecting fields and methods and annotations, thus creating a database of all information contained within the Java code.

Configuration for EJB lookups at runtime

I have several services deployed as EJBs on a JBoss-AS-7.1 server. Many applications use these EJBs by doing a lookup like this:
#EJB(lookup = "java:global/FooService/FooBean!com.xyz.FooBeanRemote")
private FooBeanRemote fooBeanRemote;
The problem is that the lookup string is hard-coded in the source. I want to be able to change this lookup at runtime - without a re-compilation - because FooService may be updated some time in the future, and perhaps have a different implementation. In addition, the ejb could also move to a different server instance.
What would be the best way to achieve this?
Use ejb-jar.xml instead of annotation (check here)
use InitialContext in your code to lookup for bean and move bean name to properties file
Implement CDI producer methods in separate jar
--EDIT---
Quick HOWTO about last point:
1. Create qualifier
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, TYPE, METHOD})
public #interface FooService {
}
2. Create producer method
public class EJBProducer {
#Produces
#FooService
#EJB(lookup = "java:global/FooService/FooBean!com.xyz.FooBeanRemote")
private FooBeanRemote fooBeanRemote;
}
3. Use in your code
#Inject #FooService
private FooBeanRemote fooBeanRemote;
Two first points may be in another jar archive (remember to include there META-INF/beans.xml file). You can also use producer method instead of field, and access ejb programmatically.

Explain RestEasy providers, resources and singletons in relation to classes vs instances?

I'm building a JAX-RS app that consists of a stockroom and a workplace. The stockroom holds a set of Java classes that can be instantiated (via AJAX) to create named instances of those classes in the workplace.
So far I'm able to reference the stockroom and workplace fine by declaring them as "singletons" in the RestEasy application
singletons.add(StockPlace.getInstance());
singletons.add(WorkPlace.getInstance());
I'm unable to understand how to understand how the stockroom content classes should be handled. The effect I'm trying to achieve is that when I dynamically create an instance of one of the stockroom classes, that instance can be dynamically accessed via REST commands. I've tried various permutations of:
classes.add(SomeComponent.class);
I think I'm missing knowledge of how the Java notion of how classes work as factories for making instances, and how both of these relate to what RestEasy calls classes, singletons (singletons ARE classes, yet RestEasy registers them as instances) and resources (instances?).
I suspect I'll wind up needing to dynamically register new instances but can't find a way to do that either. I did find a way to do it given the ServletContext, but am not able to get access to that either. Can someone get me on the right track?
Our eventual answer to this question was to bail out of RestEasy and convert to DropWizard. That problem and many others vanished and everything became easy again.
I believe I know what you are after, but I should at least give you a push in the right direction.
You will need to add the annotated RESTEasy class(es) to the registry. Below is the class I used for a recent project. It adds to the singletons (per what you did) but it also adds to the registry.
public class RESTEasyServerApplication extends javax.ws.rs.core.Application
{
// The RESTEasy registry
#Autowired
protected org.jboss.resteasy.spi.Registry registry;
// The annotated RESTEasy handler classes
private Set<Object> singletons = new HashSet<Object>();
private List<Object> handlers = new ArrayList<Object>();
public RESTEasyServerApplication()
{}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
// Spring injection support
public void setHandlers( List<Object> handlers )
{
for( Object handler : handlers )
{
if( registry != null )
{
// Save a reference to the handler
this.handlers.add( handler );
// Register the handler with RESTEasy
registry.addSingletonResource( handler );
}
singletons.add( handler );
}
}
// Spring injection support
public List<Object> getHandlers()
{
return handlers;
}
}
I used Spring, and here is the relevant configuration:
<!-- RESTeasy/Spring integration -->
<import resource="classpath:springmvc-resteasy.xml" />
<!-- RESTeasy server application -->
<bean id="application" class="blah.blah.resteasy.RESTEasyServerApplication">
<property name="handlers">
<list>
<!-- Application specific handler classes -->
<ref bean="sample"/>
</list>
</property>
</bean>
Should be easy to modify/add a method to accept a single annotated RESTEasy class and make it work dynamically as required. The registry is defined in the springmvc-resteasy.xml file.
Since I've found no answers that don't involve strapping another whole layer of complexity (Spring) onto RestEasy, the solution I found livable is outlined in the final comment above. That is, don't rely on sending remote messages to instances unless the app is truly stateless (e.g. instances don't persist across messages). Only send remote messages to singletons which do persist across requests. Each such message can identify the desired instance (by String id in my case), and the singleton can forward to the identified instance as an ordinary POJO.
I still don't see why RestEasy unconditionally treats non-Singletons (instances) as ephemeral. Statelessness is not a restriction on REST, only a restriction on when GET methods can be used (idempotent calls). PUT and POST calls are neither stateless nor idempotent.
As I understand this, of course, and feel free to correct me. My focus is getting this app on the air, not exploring every corner of RestEasy, REST, and certainly not Spring.

cannot find my bean using the InitialContext.lookup() method

I have tried to use struts 1.3 API to make a small application with EJB 3.0. Unfortunatelly i cannot use the #EJB annotation to call my bean object from inside my action class. I have solved this problem using different workarounds ( the first one is to use my global jndi name of my bean and the other is to call another class first and use the #EJB annotation from that class). Still these two workarounds have significant disadvantages. I would like to call my EJB directly from my action class. I have read plenty examples using the "java:comp/env/beanName" JNDI name but still haven't figure out how to do it and get name not found axception.
Let the full name of the local EJB class be the com.ejb.myEjbPackage.MyEJBLocal, how can i call it using the context lookup? (can i do it without modifying any of the web.xml and sun-web.xml descriptors?)
I am using glassfish server and Netbeans IDE.
Thank you in advance
#EJB won't work in a standard pojo it can only be done in a managed object (i.e. another session bean)
So...
Here's your bean
#Stateless(mappedName="beanName")
public class beanName implements beanNameRemote {
Here's your lookup
Context context = new InitialContext(); //default lookup pulls from jndi properties file
context.lookup("beanName");
You can do some further reading on the mappedName to see if you want to use it or not.
I found the answer :
If you cannot use the EJB annotation in the class you want to call the bean then :
If you don't want to mess with XML descriptors to define your bean , you have to do it in the bean class itself.
Hence i used the following annotation in the GameBean class
#Stateless
#EJB(name="ejb/GameBean",beanInterface=GameBeanLocal.class,beanName="GameBean")
public class GameBean implements GameBeanLocal {.....
The beanName is optional. The annotation must be declared in the line ABOVE the declaration of the class.
Then, in order to call the bean from the other class you can do
InitialContext ic = new InitialContext();
ic.lookup("java:comp/env/ejb/GameBean");