System wide adapter in Jersey? - java

I'm trying configure a "system wide" custom javax.xml.bind.annotation.adapters.XmlAdapter for the java.util.Locale type in Jersey. It's easy enough to use #XmlJavaTypeAdapter on classes I control but that's not always the case (3rd party code that I can't annotate).
It seems like it would be a pretty common problem but I can't find any good examples or doco on how to handle it.
So, is it possible?
Thanks!

I can see three possible options:
Register the converter with the marshaller with setAdapter(). You can have a static builder function which adds all your 'system level' type adapters to all marshallers which you use in your application. It all depends on your definition of 'system level'
Use a delegate
Do some fancy bytecode trickery to add the annotations to existing class files.
My advice would be to use approach 1, which is simple and straightforward.

If you need to annotate classes you can't modify, you could always use the externalized metadata feature of EclipseLink JAXB (MOXy).
The metadata file would look something like:
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
<java-types>
<java-type name="java.util.Locale">
<xml-java-type-adapter value="some.package.YourAdapter"/>
</java-type>
</java-types>
</xml-bindings>
To you EclipseLink MOXy you need to add a jaxb.properties file in with your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

You may also want to look at JAXBIntroductions project which is intended for similar purpose. The annotation configuration is kept in a file, without requiring modification to source code. It does work nicely with Jersey, by implementing a JAX-RS provider. You can check out my blog entry which explains this in detail with an example. Here is a simple JAXBContextResolver provide for JAXBIntroductions that can be used in your Jersey application.
import com.sun.xml.bind.api.JAXBRIContext;
import org.jboss.jaxb.intros.IntroductionsAnnotationReader;
import org.jboss.jaxb.intros.IntroductionsConfigParser;
import org.jboss.jaxb.intros.configmodel.JaxbIntros;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import java.util.*;
#Provider
public class JAXBContextResolverForJAXBIntroductions implements ContextResolver<JAXBContext> {
private final JAXBContext context;
private final Set<Class> types;
private final Class[] cTypes = {Customer.class};
public JAXBContextResolverForJAXBIntroductions() throws Exception {
this.types = new HashSet(Arrays.asList(cTypes));
JaxbIntros config = IntroductionsConfigParser.parseConfig(this.getClass().getResourceAsStream("/intro-config.xml"));
IntroductionsAnnotationReader reader = new IntroductionsAnnotationReader(config);
Map<String, Object> jaxbConfig = new HashMap<String, Object>();
jaxbConfig.put(JAXBRIContext.ANNOTATION_READER, reader);
this.context = JAXBContext.newInstance(cTypes, jaxbConfig);
}
public JAXBContext getContext(Class<?> objectType) {
return (types.contains(objectType)) ? context : null;
}
}

Related

Wildfly ignoring jackson annotations and not using #Provider class

I have looked around here and don't think this is a duplicate of any of these:
using Jackson annotations in Wildfly
jackson annotations being ignored
Wildfly and Jackson #JsonIgnore annotation
Using Wildfly 10 and deploying a war with the following class:
#Provider
public class JaxApplication implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public JaxApplication() {
mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//throw new RuntimeException("HERE");
}
#Override
public ObjectMapper getContext(Class<?> type) {
throw new RuntimeException("HERE");
//return mapper;
}
}
I see the exception in the constructor thrown when I deploy if it's not commented, but I don't see the one from the getContext method when I make a request to my REST service.
I have a #JsonIgnore annotation on an entity and it's not working, nor is the #JsonIdentityInfo annotation I'm using
That class looks like this (imports included, to verify I'm using com.fasterxml.*)
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* Created by mb995a on 7/29/2016.
*/
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#request_id", scope=Request.class)
public class Request extends BaseEntity {
Do I need to do something special in my REST config?
#ApplicationPath("api")
public class RestApplication extends Application {
public RestApplication() {
super();
}
}
Any ideas?
Edited to say: I also have a unit test that uses an ObjectMapper and it serializes properly.
For anyone else, I figured this out. The problem was that I had jackson jars in my pom that were not marked as "provided" scope. This meant that I had jars in my war file's WEB-INF/lib directory.
Even though they are the exact same version of Wildfly's jars (I use the same version properties as the WF version I'm using) they do not work properly. Looks like the hashCode() is different for the same annotation from different jars even if they are the exact same (checksum and everything).
So, the solution was to mark the dependencies as provided in maven for all Jackson stuff.

Is it possible to monkey patch a scala final class with an annotation?

I'm using Scala as my language. I'm using Google Objectify as my persistence API to store objects into Google App Engine's Datastore. Any class that is to be stored in the Google App Engine Datastore via Objectify has to have a #Entity annotation prefixing the class. You typically apply this annotation to your own classes for use in your own app or domain. In one my classes, I'd like to be able to define a class attribute of type Option[String]. In order to do that, I would need to be able to apply the #Entity or #Subclass annotation (Objectify annotations) to the Option class. But that is a built-in Scala language type. Is there a way to use implicit classes or types or Scala macros to do "monkey patching" to the language to allow me add that annotation, after-the-fact, to a built-in Scala language type?
The simplest solution would be to define your own class equivalent to Option and implicit conversions from/to Option.
Otherwise, there's no way to do so in Scala itself, but you can use one of bytecode manipulation libraries like ASM or Javassist. There is an example of adding annotations dynamically given for ASM here (but it seems incomplete) and one for Javassist here. The Javassist one seems much easier to use (not translated to Scala, but it's trivial):
import java.lang.reflect.Field;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
public class AddingAnnotationDynamically {
public static void main(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("scala.Option");
// Without the call to "makePackage()", package information is lost
cp.makePackage(cp.getClassLoader(), pkgName);
ClassFile cfile = cc.getClassFile();
ConstPool cpool = cfile.getConstPool();
AnnotationsAttribute attr =
new AnnotationsAttribute(cpool, AnnotationsAttribute.visibleTag);
Annotation annot = new Annotation(annotationName, cpool);
attr.addAnnotation(annot);
cfile.addAttribute(attr);
// Changes are not persisted without a call to "toClass()"
Class<?> c = cc.toClass();
}
}

Play 2.0/2.1 for Java and dependency injection

We have a new Play 2.0 project and we are planning to introduce DI as we add some complex 3rd party integration code.
There is a Guice plugin for Play 2.0 but it looks like it will be obsolete at 2.1 and I have a hunch that 2.1 is not that far anymore.
https://github.com/typesafehub/play-plugins/tree/master/guice
Is Guice a safe bet for Play 2.0/2.1 or should we consider other options?
I'd go with the 2.1 version, and the new controller instanciation from the Global object.
Here is a Guice example from the doc:
import play.GlobalSettings;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Global extends GlobalSettings {
private static final Injector INJECTOR = createInjector();
#Override
public <A> A getControllerInstance(Class<A> controllerClass) throws Exception {
return INJECTOR.getInstance(controllerClass);
}
private static Injector createInjector() {
return Guice.createInjector();
}
}
You have to declare a special route for these controllers, with the special #:
GET /myUrl #controllers.MyController.myMethod()
And you can also take a look at this demo using Spring: https://github.com/guillaumebort/play20-spring-demo

Loading multiple annotated classes in Hibernate

I am using hibernate annotations and for that in the hibernate.cfg.xml i need to add annotated classes like this <mapping class="p.Customer" /> here p is the package name and Customer is the annotated bean.
Suppose i have 20 such kind of annotated classes, it means I have to write 20 mapping lines for that class.In Spring there is a property packageToScan that can be used to register/load all hibernate annotated classes in the specified package.
Since I am not using Spring, can we have the same functionality in Hibernate?
Also I found one tag in hibernate.cfg.xml <mapping package="" /> at first I thought this will do the job for me, but it didn't work. I didn't get what is the use of this property.
The magic of annotations parsing is done when creating session factory. Hibernate can do it without spring. Spring actually just wraps the hibernate functionality.
Please take a look on this article: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-overview
They show how to register classes in session factory, so the annotations are used. They indeed do not provide functionality of scanning but you can either implement it yourself or better use other package. I used "reflections" package for similar purpose. I mean I scanned my classpath to locate classes according to my criteria using reflections package. I did not use it for hibernate but I am sure it is possible.
Here is the reference that can help you.
http://code.google.com/p/reflections/
1,refer :
How to get all classes names in a package?
2,extend org.hibernate.cfg.Configuration
`
package com.hw.configuration;
import com.hw.util.ClassFinder;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import java.util.List;
/**
* Created by whuanghkl on 17/5/31.
*/
public class WildCardConfiguration extends Configuration {
#Override
public Configuration addPackage(String packageName) throws MappingException {
List<Class<?>> classes = ClassFinder.find(packageName);
int size=classes.size();
for (int i=0;i<size;i++){
super.addAnnotatedClass(classes.get(i));
}
return this;
}
}
`
3,
`
new SchemaExport(new
WildCardConfiguration().configure()).create(true, false);
`

Is it possible to include all javascripts files from one folder in JSF?

I am using JSF 2.0, and am looking for a means to include all the javascripts from a given folder on a page, i.e. do something like
<h:outputScript library="javascript" name="*.js" target="head" />
Is this kind of thing even possible? Should I write a custom component using java code to achieve this?
Thanks for your help,
Sébastien Tromp
Nice idea. This is not supported by the JSF API, but it's in theory possible with a custom script renderer. I played somewhat around it and it's indeed possible. Just create a MultiScriptRenderer which extends ScriptRenderer and override encodeEnd() to check if the name attribute contains the * wildcard and then handle accordingly by scanning for files matching this pattern in the resources folder.
Here's a kickoff example:
package com.example;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import com.sun.faces.renderkit.html_basic.ScriptRenderer;
public class MultiScriptRenderer extends ScriptRenderer {
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
Map<String, Object> attributes = component.getAttributes();
String name = (String) attributes.get("name");
if (name.contains("*")) {
String pattern = name.replace(".", "\\.").replace("*", ".*");
String library = (String) attributes.get("library");
File root = new File(context.getExternalContext().getRealPath("/resources/" + (library != null ? library : "")));
for (File file : root.listFiles()) {
if (file.getName().matches(pattern)) {
attributes.put("name", file.getName());
super.encodeEnd(context, component);
}
}
attributes.put("name", name); // Put original name back. You never know.
} else {
super.encodeEnd(context, component);
}
}
}
Register it in faces-config.xml as follows (Sorry, #FacesRenderer annotation isn't going to work until it's fixed in JSF 2.2 for this specific corner case, see also JSF issue 1748):
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.resource.Script</renderer-type>
<renderer-class>com.example.MultiScriptRenderer</renderer-class>
</renderer>
</render-kit>
Works fine on Mojarra 2.0.3 here. You can use patterns like *.js and prefix*.js. The particular code example is only tight coupled to a specific JSF implementation to save code boilerplate. It also requires that the WAR is expanded on deploy, otherwise browsing the directory by File#listFiles() won't be possible (which thus excludes certain (older) servletcontainer versions/configurations). For other JSF implementations you'll have to extend its ScriptRenderer instead, or write a whole new one if you want to be implementation independent (which should be pretty simple though, just look at standard ScriptRenderer source if you stucks).
I didn't test this, but if wildcards are not accepted, you could fetch the filelist via java code in a backing bean, and insert them into head using c:forEach or ui:repeat like:
<ui:repeat value="#{bean.files}" var="file">
<h:outputScript library="javascript" name="#{file}" target="head" />
</ui:repeat>
Note that you cannot give absolute paths to h:outputScript but you must extract the prefix from them (the part the preceeds the JSF resources path).

Categories