My colleague Kevin and I are working on the Service Oriented Architecture team at our retail employer. The idea is to pilot a project to get us going for real down the SOA road. We're evaluating tools like Aqua Logic, WebLogic 10, and Sun's Glassfish, and working with the new APIs in Java SE 6 and Java EE 5, including JAXB 2.0, JAX-WS to build services, and so forth. So I thought I would post some of our fidings here every once in a while that might be useful to others working with similiar technologies.
We have a WebService that accepts a complex custom type, and returns a String. The service is an EJB 3 Stateless Session Bean, and we're using simple Java models for a "Start from Java" development process. We're agreed that we won't add annotations or anything to the classpath that isn't absolutely necessary. We don't even have an interface for our EJB, because you don't need it (let alone leaking the implementation out to the interface with @Local or @Remote, rendering the presence of the interface itself totally redundant and useless qua interface).
We decided to wrap the String that our operation returns in more useful custom type (called BinInfo), and suddenly our Ant deployment task (for Glassfish b47) died with the following error:
The exception message is: CLI171 Command deploy failed : Deploying application in domain failed; Unable to create JAXBContext due to the security restriction
It seemed our WebService could somehow accept a custom type, but not return one. What was the problem? Looking on the Glassfish forum revealed that other users had a similar problem, but their solutions didn't work for us. Posts there indicate that 1) you need to have a default no-arg constructor in custom types you use as parameters or return types in your web service operations, including Sun-provided classes like Locale and 2) that the deploy-time exception does not get reported properly by Glassfish. So if your class does, as ours does, really have a default no-arg constructor, you could be flummoxed. This is all standard XML marshalling stuff, so what to do?
There are two ways to deal with this situation. If your problem is the no-arg constructor situation, you can add one and see if that clears it up. There are obvious design reasons not to blindly go that route, however.
Second way: if that's your problem but it's not in a class you wrote or can change or want to change, you can use the standard Java SE 6 annotation @XmlJavaTypeAdapter(YourAdapterImpl.class) to indicate to the marshaller exactly how it should deal with this absence. There is a concise and helpful article on the subject here, so I won't go into it:
http://weblogs.java.net/blog/kohsuke/archive/2005/09/using_jaxb_20s.html
But what if you do, as we do, actually have a default no-arg constructor, have an object simple enough that creating a new class to implement @XmlJavaTypeAdapter is overkill (not to mention misleading for future maintainers of the code and does not address the root of the problem) and the error message is hidden from you? Directly use the tool that Glassfish uses under the hood: schemagen.
If the Java tools in the JDK bin directory are on your path (they should be) then you can open a prompt, type "schemagen" and use that tool to generate your XML schema representation. Navigate to the directory with the Java source file that is giving you problems. For us it was BinInfo.java.
Here was our class:
public class BinInfo {
public String chargeType;
public BinInfo() { }
public void setChargeType(String chargeType) {
this.chargeType = chargeType;
}
public String getChargeType() {
return chargeType;
}
}
A perfectly normal, simple bean, right?
Running schemagen BinfInfo.java produced the following error:
[ehewitt@dtc20266w domain]$ schemagen BinInfo.java
error: Class has two properties of the same name "chargeType"
this problem is related to the following location:
at mypackage.BinInfo.getChargeType(BinInfo.java:28)
at mypackage.BinInfo(BinInfo.java:16)
this problem is related to the following location:
at mypackage.BinInfo.chargeType(BinInfo.java:18)
at mypackage.BinInfo(BinInfo.java:16)
1 error
This reveals that the field was accidentally typed to be "public", and schemagen thinks that the field itself and the getter method for it are the same. I changed the visibility of the field to private and everything worked fine.
While hopefully your typing skills are better than mine, this post is meant to illustrate that you can use schemagen to get a clear picture of what the deployment tools are doing, and highlight mistakes in your code. This is important because Glassfish isn't percolating nested exceptions up at this time, and the error messages are misleading at best ("the security restriction"???) .
Thank you VERY much for your post!
Posted by: Grateful | July 06, 2007 at 08:33 AM
Thanks for this - java.sql.Timestamp it seems does not have a default no-args contstructor but once I changed all my usage to Calendar it works a treat. Pity the error messages are so dreadful in Glassfish but thanks for the help !
Posted by: Rich Livingstone | September 21, 2007 at 08:57 AM
Adding underscores to my private pojo fields fix the problem.
public class SimplePojo implements Serializable{
private String _name;
private int _idPojo;
public String getName() {
return _name;
}
public int getIdPojo() {
return _idPojo;
}
public void setName(String name) {
this._name = name;
}
public void setIdPojo(int idPojo) {
this._idPojo = idPojo;
}
public SimplePojo(){}
public SimplePojo(int idPojo,String name)
{
this._idPojo = idPojo;
this._name = name;
}
}
Posted by: matboul | April 01, 2008 at 09:00 AM
Your problem is a little different. It has to do with the default behaviour of what is used as xmlelement. I want to explicit tag my members with the @XmlElement.
I needed to add @XmlAccessorType(XmlAccessType.NONE) to indicate that only annotated values should be handled.
Posted by: Johan C. Stöver | September 26, 2008 at 02:03 PM
Hi, I have a problem with a exception class that I use to returns exceptions to the client:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package serviciosweb;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService()
public class MapperException extends Exception{
private static final long serialVersionUID = 1L;
public MapperException(){
super();
}
@WebMethod
public void voidMethod(){
}
}
I don't know the way...
Thankyou.
Posted by: paco | May 10, 2009 at 01:07 PM
I'm sorry, but I haven't explained all...When I call this web service in my PC (localhost) works well (without use your solution), but when I call in another PC (in the same LAN) doesn't work...
Posted by: paco | May 10, 2009 at 01:15 PM