Reputation: 6222
I have a jar with the model DTOs.
I want these classes (marked with @XmlRootElement
) to be available to Jersey 1 HTTP client. My initialization code is:
ClientConfig cc = new DefaultClientConfig(MyContextResolver.class);
Client client = Client.create(cc);
In MyContextResolver
(which implements ContextResolver<JAXBContext>
), I've tried:
jaxbContext = JAXBContext.newInstance(Class1.class, Class2.class);
It works, but it's not dynamic (I have to add classes manually, one by one).
I also used Spring and it worked, but I want a Spring free solution.
Is there a better solution? One that automatically scans all classes in the jar and adds them to the context? Thanks.
Upvotes: 0
Views: 1116
Reputation: 6222
I ended up scanning the jar manually...
public static List<Class> listClassesInPackage(String jarName, String packageName) throws IOException {
packageName = packageName.replaceAll("\\.", "/");
JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
JarEntry jarEntry = null;
List<Class> classes = new ArrayList();
do {
try {
jarEntry = jarFile.getNextJarEntry();
if (jarEntry != null && jarEntry.getName().startsWith(packageName) && jarEntry.getName().endsWith(".class")) {
Class<?> forName = Class.forName(jarEntry.getName().replaceAll("/", "\\.").replaceAll(".class", ""));
XmlRootElement xmlAnnotation = forName.getAnnotation(XmlRootElement.class);
if (xmlAnnotation != null) {
classes.add(forName);
}
}
} catch (ClassNotFoundException | IOException ex) {
// ignore this class
}
} while (jarEntry != null);
return classes;
}
invocation:
List<Class> packageClasses = listClassesInPackage(
Meta.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "pt.iol.model2");
jaxbContext = JAXBContext.newInstance(packageClasses.toArray(new Class[0]));
Upvotes: 0
Reputation: 8562
Is there a reason why you want to have a context that handles all the classes at the same time? You are risking an exception if you have names clashes.
Why not simply have a ContextResolver that works like:
Map<Class,JAXBContect> cache = new ConcurrentHashMap<>();
getContext(Class<?> type) {
JAXBContect context = cache.get(type);
if (context == null) }
context = JAXBContext.newInstance(type);
cache.put(type,context);
}
return context;
}
JAXB will resolve the necessary classes dependencies (the only problem are subclasses but those should be marked @XMLSeeAlso in the parrent class).
The only potential problem is that you will find out of any JAXB problem during runtime not during startup. But at the same time any error will affect only the clients dependent on wrongly annotated classes and the rest will work.
Upvotes: 1