I have REST (Jersey) webservice that makes use of some data objects that are marshalled/unmarshalled to/from XML. The data objects are in a separate project/jar that the webservice war depends on.
I'm using MOXy as my JAXB implementation since I'm deploying to Glassfish and that's already included. I know I need a jaxb.properties file to set the JAXB implementation to MOXy with this entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
The question is, should the jaxb.properties file be included in the data object jar or in the webservice war or both?
If you don't want or can not use the jaxb.properties (you have a lot of package, the model is in a external jar, you want only java and no configuration files...), you can directly specify the JaxbContextFactory :
Do not create the context using :
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{Person.class, ObjectFactory.class}, properties);
But instead, specify the factory to use :
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[]{Person.class, ObjectFactory.class}, properties);
where the factory is :
import org.eclipse.persistence.jaxb.JAXBContextFactory;
It is exactly the same, but it is specified explicitly in the java code instead of implicitly in a configuration file.
You package the jaxb.properties file with your model classes. GlassFish does not include the MOXy bundle yet, but you can add it easily. Check out my blog for more info:
http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-35.html
Related
I'd like to include a resource file (e.g. some xml config file) in my bundle and make it visible to all other bundles in the container. Is it possible without using the Fragment-Host manifest header? I'd like this resource file to always be visible in the classpath of all bundles running alongside my bundle, even those that do not exist yet, but will potentially be added in future.
EDIT:
To clarify - that resource must be available passively, i.e. the other bundles should be able to find it in their classpath, and not by refering to any special API or service of my bundle.
Some more background - my environment is a bit messy but I have no control over it and cannot change its existing bundles. The only way I can modify it is by adding my own bundles. That environment includes several copies of the ch.qos.logback.classic bundle. When logback starts up, it looks for specific XML config files in the classpath. If it doesn't find any of them, then its default behaviour is to print everything to stdout with debug level. This environment was previously used to host a GUI application so it didn't matter that much before, but now I am trying to adapt it so I can use some of its functionality in headless mode. So now it becomes important to me to be able to configure it in such a way that only warning and errors are printed to the console.
In general, no you cannot do this. Class-space isolation is at the heart of OSGi, but you want to put a resource in the class loader of one bundle and make it visible to all other bundles. That's not OSGi, it's the global application classpath.
The only thing you can do to add to the internal classpath of a specific bundle is to write a fragment which attaches to that bundle. A fragment can attach to multiple host bundles, but only if those hosts have the same symbolic name, i.e. because they are different versions of the same bundle. See OSGi R6 Core Specification, section 3.14.
You did however state that the bundles you want to attach are all copies of ch.qos.logback.classic. If that means they all have that exact symbolic name then perhaps a fragment will work after all.
You can not change the classpath of other bundles this way.
What you can do is retrieve the classloader of your bundle from your bundleContext. You can give this classloader to another bundle to retrieve your resource.
ClassLoader cl = context.getBundle().adapt(BundleWiring.class).getClassLoader();
Another option is to give the other bundle the URL of the resource.
As long as the resource is on the classpath, any bundle can access the resource if it can get hold of the class loader of the bundle that contains the resource.
For example:
ClassLoader classLoaderOfBundleWithResource = ...
classLoaderOfBundleWithResource.getResourceAsStream("org/example/resource.xml");
From a maintenance and API point of view, I would not recommend exposing a resource that way. Java types are much better suited therefore. Instead, let the resource bundle export a class that gives clients access to the contents of the resource.
For example:
public class XmlDocumentProvider {
public InputStream openDocument() {
return getClass().getResourceAsStream("resource.xml");
}
}
Assuming that both the resource.xml and the XmlDocumentProvider reside in the same package, openDocument will return the resource content just like in the first example.
How could I read properties form a separate file in Spring Boot ?
I'm trying what he's doing here.. http://www.mkyong.com/spring/spring-propertysources-example/
But it doesn't read the file?
say you have a file.properties in the resources folder.
you should put :
spring.configuration.location: classpath:file.properties
in application.properties to point to the file.
Then in your MyConfig class
#Service
public class MyConfig{
#Value("${prop.one}")
private String propOne;
Shouldn't this work? what am I doing wrong
Is there a simple example of doing this somewhere?
Thanks!
The simplest way to do this is to create an application.properties that will reside at the root of your jar
src
main
resources
application.properties
Spring boot will autoload this file as a properties file. This is a special feature of spring boot to look for the application.properties automatically. With regular Spring, you need to specify where the properties file is. They are demonstrating how to add a new properties file with regular spring.
For a separate properties file from the standard application.properties, you can add the #PropertySource annotation to your configuration class. This annotation will load the properties into the spring environment.
I have an .ear file with the standard lib directory.
I have a .jar file in that lib directory. It contains UserInfoManager, which is an interface. It contains (for these purposes) no other classes. It also contains a META-INF/beans.xml file.
I have another .jar file in that lib directory. It contains a class named UserInfoResource that is a JAX-RS resource class. That class has the following inside it:
#Inject
private UserInfoManager userManager;
Next, I have an EJB .jar file at the root of the .ear file. It contains a class named UserManagerBean that implements the UserInfoManager interface. This class is annotated with #Stateless and basically nothing else (thus making it a local stateless session bean exposed via its local business interface (UserInfoManager). This .jar file also has a META-INF/beans.xml file.
Next, I have a .war file with an Application class in it and nothing else. This serves as the "mounting point" for any and all JAX-RS resources discovered at deployment time present in the lib directory. I do not declare this Java EE 6 module as a CDI bean archive since it contains no beans.
This spec-compliant arrangement fails at deployment time. Weld (the CDI implementation in GlassFish 3.1.2) claims that the injection point detailed above cannot be satisfied, as there are no known implementations of UserInfoManager available to it.
When that injection point is annotated with #EJB instead, everything works fine.
How do I get CDI to inject a local stateless session bean reference into a JAX-RS resource that is present on the classpath?
Update: Because no matter how I look at this it seems like a specification violation, I have filed a bug with a testcase attached. I encourage readers to take a look and see if they can get it to work.
Update: The workaround is to make sure that your JAX-RS classes are not bean archives, but are annotated with #ManagedBean. In addition, the {{.war}} file that serves as their mount point must be a bean archive (must have a {{WEB-INF/beans.xml}} file). Some combination of these requirements is a CDI specification violation. The following bug tracks these issues: http://java.net/jira/browse/GLASSFISH-18793
Jersey does not treat Resources as managed beans unless there is an explicit scope/#ManagedBean annotation attached to it. So, you need to annotate your resource with #ManagedBean or #RequestScoped for the injection to work.
Seems the problem occurs only if beans.xml is included in the resource jar file. When I remove it and attach #ManagedBean annotation to the resource class (instead of #RequestScoped, since #RequestScoped does not work if no beans.xml is present) it works. I am not a CDI expert, so not sure if this is as designed or a bug.
This is for Struts 1.x (I'm using 1.3.10).
I've noticed that Struts is unable to pick up resource bundles in the ApplicationResources.properties file if it is not placed somewhere in the default classpath (e.g., com.abc.SomePackage).
For instance, if I put the ApplicationResources.properties file in a custom folder /WEB-INF/strutsResources and configure the struts-config.xml thus:
<message-resources parameter="/WEB-INF/strutsResources/ApplicationResources"/>
I've read that the resources need to be on the classpath so I've also tried adding the /WEB-INF/strutsResources folder to the classpath. It still does not pick up the resource keys.
I've double-checked that the strutsResources folder is actually deployed to the server (I'm using Glassfish v3), so the file is there, it's just not being parsed.
P.S.
If you're wondering why I'm trying to do this, I just wanted to organize my code a little better ("better," IMO). Since the ApplicationResources.properties file is not really a class, I wanted to place it in a resources folder by itself.
I've checked that placing the ApplicationResources file in a package in the src directory works just fine.
Ultimately, the answer is yes. You can play some interesting games by configuring a custom className and/or factory and get messages however you want (including from a database) and so on. This allows you to customize whatever you want*.
I agree the resources aren't a class, but putting them on the classpath is a common practice, and allows resources to be loaded as a resource, e.g., from inside a jar. I'm sympathetic, but I'd leave it as-is.
*Like reversing all the text; a fun prank to play on your co-workers and QA department.
Its best leave it on the classpath.
It's stadard practise to include properties files on the classpath, especially if you're planning on packaging it up in your WAR/EAR. You're keeping it under WEB-INF so you gain no benefit from moving it off the classpath, and you'll just confuse other developers who have to work on the project and you've had to put a hack in to make this work.
If you want to keep your files external to your deployable WAR/EAR then that's a valid reason for not using the classpath. Typically this will require some configuration as part of your deployment to specify where the file is to reside.
For example specify the location using
a JVM argument (e.g. -Dprops.file=/config/myapp.properites)
lookup from a JNDI resource
use a PropertiesFactoryBean if you're using the Spring framework (I
use Spring's ApplicationContext with Struts 1 MVC)
read properties from a database writing your own
ApplicationPropertiesDAO class that initialises itself durnig your
applications bootstrap process (e.g. Spring application contact,
Servlet in web.xml, Listener in web.xml, etc)
I'm happily using the Maven bundle-plugin to create OSGi manifest headers for my modules. However, when there are configuration files that pull in classes which aren't referenced directly in the code, the plugin can't tell which packages it's going to need.
One example is a bundle with domain models that constitute a Persistence Unit for JPA. The driver class is part of the PU configuration and either set in an XML file or at runtime when the EntityManager is instantiated. I have to manually add an Import-Package header for the driver class that I want to load, or I get CNF errors.
Another example is a Struts war, where the web.xml pulls in the Struts dispatcher that's otherwise not found anywhere in the code and has to be manually added to the headers.
How can I avoid this?
I tried adding the required packages as dependencies with a provided scope, but that didn't help.
In the plug-in section of the bnd configuration you can specify plug-ins to analyze these files and contribute to the import-package header. For spring it looks like this:
<_plugin>aQute.lib.spring.SpringComponent</_plugin>
I am not sure, what descriptors are supported on top of spring. Just take a look at the source (it's in the Apache Felix SVN) and see for yourself. In the worst case you have to write your own plug-in, but at least it is possible! Also peter kriens site about the bnd explains the usage and some internals.
Other then that I am not aware of any simple solution.