[ https://issues.apache.org/jira/browse/CXF-4016?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Daniel Kulp resolved CXF-4016. ------------------------------ Resolution: Fixed Fix Version/s: 2.5.2 2.4.6 Fixed. Two comments: 1)While writing my test, I was actually getting an Exception thrown instead of the element without a type. Might be a difference on trunk/2.6 though. 2) You could likely work around this by adding a name="ExceptionMessage" attribute to the @XmlType annotation to make it generate the type as a top level type, not an anonymous type in an element. > JAX-WS schema generation of an Exception annoted with @WebFault that contains > a property of a class annotated with @XmlRootElement causes the schema of the > WSDL to generate the incorrectly > -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > > Key: CXF-4016 > URL: https://issues.apache.org/jira/browse/CXF-4016 > Project: CXF > Issue Type: Bug > Components: JAX-WS Runtime > Affects Versions: 2.4 > Reporter: Vincent Furlanetto > Assignee: Daniel Kulp > Fix For: 2.4.6, 2.5.2 > > > I have the following Exception Class (BusinessException) that is annotated > with @WebFault. BusinessException has a property named exceptionMessage that > is of Type ExceptionMessage. ExceptionMessage is annotated with the > @XmlRootElement annotation. > When CXF generates the WSDL via hitting the web wervice URL it generates a > schema with an invalid element for the BusinessException element. > See the schema in question here: > {code} > <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" > targetNamespace="http://www.mycompany.com/platform/exception" > xmlns:tns="http://www.mycompany.com/platform/exception" > xmlns:xs="http://www.w3.org/2001/XMLSchema"> > <xs:element name="ExceptionMessage" type="tns:exceptionMessage"/> > <xs:complexType name="exceptionMessage"> > <xs:sequence> > <xs:element minOccurs="0" name="classCause" type="xs:string"/> > <xs:element minOccurs="0" name="severity" type="xs:string"/> > <xs:element minOccurs="0" name="exceptionMessage" type="xs:string"/> > <xs:element minOccurs="0" name="displayMessage" type="xs:string"/> > <xs:element name="code" type="xs:int"/> > <xs:element minOccurs="0" name="informationCode" type="xs:string"/> > <xs:element minOccurs="0" name="uniqueID" type="xs:string"/> > <xs:element minOccurs="0" name="userResolution" type="xs:string"/> > <xs:element minOccurs="0" name="exceptionCause" type="xs:string"/> > <xs:element minOccurs="0" name="stack" type="xs:string"/> > </xs:sequence> > </xs:complexType> > <xs:complexType name="BusinessException"> > <xs:sequence> > <xs:element nillable="true"/> > </xs:sequence> > </xs:complexType> > <xs:element name="BusinessException" type="tns:BusinessException"/> > </xs:schema> > {code} > Notice this portion of the schema here: > {code} > <xs:complexType name="BusinessException"> > <xs:sequence> > <xs:element nillable="true"/> > </xs:sequence> > </xs:complexType> > {code} > It is generating an invalid schema element "<xs:element nillable="true"/>" > without a name or ref. > The problem appears to be with the fact that the ExceptionMessage class is > annotated with @XmlRootElement. If I remove the @XmlRootElement from the > ExceptionMessage class it all works fine. My problem is that the > ExceptionMessage class is also used by other services in my code that need to > serialize the ExceptionMessage to xml via JAXB. And as I'm sure you already > know when using the JaxbContext will throw an Exception if the class is not > annotated with the @XmlRootElement. I have been able to work around this > issue by simply removing the @XmlRootElement annotation and programmatically > implementing a JAXBElement object which will then allow me to use the > JaxbContext without getting the non present @XmlRootElement Exception. > {code} > QName qName = new QName("http://www.mycompany.com/platform/exception", > "ExceptionMessage"); > JAXBElement<ExceptionMessage> jaxbElement = new > JAXBElement<ExceptionMessage>(qName, ExceptionMessage.class, > exceptionMessageObj); > {code} > So I guess what I'm asking is isn't it possible just use the simple class > name for the WSDL schema name for a class that is annotated with > @XmlRootElement verus generating an invalid schema element without a name or > ref? > Please see the code example below: > {code} > package com.mycompany.platform.exception.checked; > import java.io.Serializable; > import javax.xml.ws.WebFault; > /** > * <code>BusinessException</code>- > * > * Base class for business exceptions. It is only used by application > developer. > * Caller should have knowledge about how to handle this exception. > * > */ > @WebFault(name = "BusinessException", targetNamespace = > AbstractException.TARGET_NAMESPACE) > public class BusinessException extends AbstractException { > /** > * The exception message > */ > private ExceptionMessage exceptionMessage; > /** > * Serial Version ID to compare if the class version has changed in > * serialization/deserialization. > */ > private static final long serialVersionUID = -4466271192745954077L; > /** > * Default logical exception code > */ > private static final String INFO_CODE = "error.business"; > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final Throwable nested) { > super(nested); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final String msg, final Throwable nested, > final String newInfoCode, final Serializable... args) { > super(msg, nested, newInfoCode, args); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final String msg, final String newInfoCode, > final Serializable... args) { > super(msg, newInfoCode, args); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final String msg, final Throwable nested) { > super(msg, nested); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final Throwable nested, final String > newInfoCode) { > super(nested, newInfoCode); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException(final String msg) { > super(msg); > } > /** > * @see com.mycompany.platform.exception.checked.AbstractException > */ > public BusinessException() { > super(); > } > /** > * <code>getDefaultInformationCode</code>- > * > * Returns the default exception key to use if none is specified when > the > * exception is thrown. > * > * @return <code>String</code> default information code > */ > @Override > public String getDefaultInformationCode() { > return INFO_CODE; > } > > public ExceptionMessage getExceptionMessage() { > return exceptionMessage; > } > public void setExceptionMessage(final ExceptionMessage > exceptionMessage) { > this.exceptionMessage = exceptionMessage; > } > } > package com.mycompany.platform.exception.checked; > import javax.xml.bind.annotation.XmlRootElement; > import javax.xml.bind.annotation.XmlType; > /** > * > * <code>ExceptionMessage</code>- > * > * The ExceptionMessage object that is used in the application to create > * and utilize error messages. This object provides methods to create an > * ExceptionMessage object and setters/getters for its various attributes. > * > */ > @XmlRootElement(name = "ExceptionMessage") > @XmlType(propOrder = { > "classCause", > "severity", > "exceptionMessage", > "displayMessage", > "code", > "informationCode", > "uniqueID", > "userResolution", > "exceptionCause", > "stack" > }) > public class ExceptionMessage { > /** > * WARN <code>String</code> definition > */ > public static final String WARN = "WARN"; > /** > * DEBUG <code>String</code> definition > */ > public static final String DEBUG = "DEBUG"; > /** > * ERROR <code>String</code> definition > */ > public static final String ERROR = "ERROR"; > /** > * FATAL <code>String</code> definition > */ > public static final String FATAL = "FATAL"; > /** > * INFO <code>String</code> definition > */ > public static final String INFO = "INFO"; > /** > * PERIOD <code>String</code> definition. Generates a new line. > */ > private static final String PERIOD = ".\n"; > private String displayMessage; > private String severity; > private String informationCode; > private String userResolution; > private String uniqueID; > private String stack; > private String exceptionCause; > private String exceptionMsg; > private String classCause; > private int code; > /** > * Creates a new <code>ExceptionMessage</code> object. > */ > public ExceptionMessage() { > super(); > } > /** > * Creates a new <code>ExceptionMessage</code> object. > * > * @param informationCode <code>String<code> information code > * @param theMessage <code>String</code> textual error message > * @param theCode <code>String</code> error message code > * @param theSeverity <code>String</code> error severity > * @param theUserResolution <code>String</code> user resolution > */ > public ExceptionMessage(final String informationCode, > final String theMessage, final int theCode, > final String theSeverity, final String theUserResolution) { > this.displayMessage = theMessage.replace("\"", ""); > this.code = theCode; > this.severity = theSeverity; > this.informationCode = informationCode; > this.userResolution = theUserResolution.replace("\"", ""); > } > public void setInformationCode(String informationCode) { > this.informationCode = informationCode; > } > public void setUserResolution(String userResolution) { > this.userResolution = userResolution.replace("\"", ""); > } > /** > * <code>getClassCause</code>- > * Returns the <code>String<code> Class name that caused the exception. > * > * @return <code>String<code> Class name that caused the exception > */ > public String getClassCause() { > return classCause; > } > /** > * <code>setClassCause</code>- > * Sets the <code>String<code> Class name that caused the exception. > * > * @param classCause <code>String<code> Class name that caused the > exception > */ > public void setClassCause(String classCause) { > this.classCause = classCause; > } > /** > * <code>setCode</code>- > * > * Sets the code. > * > * @param theCode <code>int</code> to set > * > */ > public void setCode(final int theCode) { > this.code = theCode; > } > /** > * <code>getCode</code>- > * > * Returns the code. > * > * @return <code>int<code> code > */ > public int getCode() { > return this.code; > } > /** > * <code>setDisplayMessage</code>- > * > * Sets the message. > * > * @param aDisplayMessage <code>String</code> to set > * > */ > public void setDisplayMessage(final String aDisplayMessage) { > this.displayMessage = aDisplayMessage.replace("\"", ""); > } > /** > * <code>getDisplayMessage</code>- > * > * Returns the message. > * > * @return <code>String</code> display message > */ > public String getDisplayMessage() { > return this.displayMessage; > } > /** > * <code>setSeverity</code>- > * > * Sets the severity. > * > * @param theSeverity <code>String</code> to set > * > */ > public void setSeverity(final String theSeverity) { > this.severity = theSeverity; > } > /** > * <code>getSeverity</code>- > * > * Returns the severity. > * > * @return <code>String</code> severity > */ > public String getSeverity() { > return this.severity; > } > /** > * <code>getInformationCode</code>- > * > * Returns the logicalName > * > * @return <code>String</code> information code > * > */ > public String getInformationCode() { > return this.informationCode; > } > /** > * <code>getUserResolution</code>- > * > * Returns the userResolution. > * > * @return <code>String</code> user resolution > * > */ > public String getUserResolution() { > return this.userResolution; > } > /** > * <code>getUniqueID</code>- > * > * Returns the unique id for the exception > * > * @return <code>String</code> Unique ID > */ > public String getUniqueID() { > return this.uniqueID; > } > /** > * <code>setUniqueID</code>- > * > * Sets the unique id for the exception > * > * @param uniqueID <code>String</code> to set > */ > public void setUniqueID(final String uniqueID) { > this.uniqueID = uniqueID; > } > /** > * <code>getStack</code>- > * > * Gets the stack trace of the exception that occurred > * > * @return <code>String</code> containing exception stack > */ > public String getStack() { > return stack; > } > /** > * <code>setStack</code>- > * Sets the stack trace of the exception that occurred > * > * @param stackTraceElements <code>String</code> representation of the > stack to set > * > */ > public void setStack( > final String stack) { > this.stack = stack; > } > /** > * <code>setStackTrace</code>- > * Sets the stack trace of the exception that occurred > * > * @param stackTraceElements <code>StackTraceElement</code> array to set > * > */ > public void setStackTrace( > final StackTraceElement[] stack) { > if (stack != null) > { > StringBuilder builder = new StringBuilder(); > this.stack = ExceptionMessage.convert(builder, > stack).toString(); > } > } > /** > * <code>getExceptionCause</code>- > * > * This method returns the original exception cause. A cause is another > * <code>Throwable</code> that caused the final exception to be thrown. > * It is also known as the chained exception facility, as the cause can, > * itself, have a cause, and so on, > * leading to a "chain" of exceptions, each caused by another. Please note > * that this cause may return null if no cause was set using the @see > * {@link ExceptionMessage.setExceptionCause()} method. > * > * @return <code>String</code> representation of the > <code>Throwable</code> chained that was set > */ > public String getExceptionCause() { > return this.exceptionCause; > } > /** > * <code>setExceptionCause</code>- > * > * This method sets the original exception cause. A cause is another > * <code>Throwable</code> that caused the final exception to be thrown. > The cause > * facility was added new in release 1.4. It is also known as the chained > * exception facility, as the cause can, itself, have a cause, and so on, > * leading to a "chain" of exceptions, each caused by another. this is > * OPTIONAL value and only to be used if there is a strong need to display > * the cause of the exception. > * > * @param exceptionCause <code>String</code> representation of > <code>Throwable</code> chained exception to set > */ > public void setExceptionCause(final String exceptionCause) { > this.exceptionCause = exceptionCause; > } > /** > * <code>setExceptionCausing</code>- > * > * This method sets the original exception cause. A cause is another > * <code>Throwable</code> that caused the final exception to be thrown. > The cause > * facility was added new in release 1.4. It is also known as the chained > * exception facility, as the cause can, itself, have a cause, and so on, > * leading to a "chain" of exceptions, each caused by another. this is > * OPTIONAL value and only to be used if there is a strong need to display > * the cause of the exception. > * > * @param exceptionCause <code>Throwable</code> exception to set > */ > public void setExceptionCausing(final Throwable exceptionCausing) { > this.exceptionCause = exceptionCausing.toString(); > } > /** > * <code>getExceptionMessage</code>- > * > * Returns the detail message string of this throwable. The detail message > * string of this <code>Throwable</code> instance (which may be null). > * > * @return <code>String</code> exceptionMessage > */ > public String getExceptionMessage() { > return this.exceptionMsg; > } > /** > * <code>setExceptionMessage</code>- > * > * Sets the detail message string of the <code>Throwable<code> that the > exception > * message may use to display. this is optional and may not always be set. > * > * @param exceptionMessage <code>String</code> exception message to set. > * > */ > public void setExceptionMessage(final String exceptionMessage) { > this.exceptionMsg = exceptionMessage; > } > /* (non-Javadoc) > * @see java.lang.Object#toString() > */ > @Override > public String toString() { > final StringBuilder stringBuilder = new StringBuilder(); > stringBuilder.append("Unique ID: "); > stringBuilder.append(this.uniqueID); > stringBuilder.append(PERIOD); > stringBuilder.append("Information Code: "); > stringBuilder.append(this.informationCode); > stringBuilder.append(PERIOD); > stringBuilder.append("Error Code: "); > stringBuilder.append(this.code); > stringBuilder.append(PERIOD); > stringBuilder.append("User Message: "); > stringBuilder.append(this.displayMessage); > stringBuilder.append(PERIOD); > stringBuilder.append("Message: "); > stringBuilder.append(this.exceptionMsg); > stringBuilder.append(PERIOD); > stringBuilder.append("Resolution: "); > stringBuilder.append(this.userResolution); > stringBuilder.append(PERIOD); > stringBuilder.append("Exception Class: "); > stringBuilder.append(this.classCause); > stringBuilder.append(PERIOD); > stringBuilder.append("Detailed Stack Trace: "); > stringBuilder.append(this.stack); > stringBuilder.append(PERIOD); > stringBuilder.append("Cause: "); > stringBuilder.append(this.exceptionCause); > return stringBuilder.toString(); > } > /** > * <code>convert</code>- > * > * Converts the stack trace of an exception into > <code>StringBuilder</code> from <code>StackTraceElement</code>. > * > * @param newStringBuilder <code>StringBuilder</code> buffer to which > will be appended > * @param stack <code>StackTraceElement</code> array of elements to > append to the stack > * > * @return <code>StringBuilder</code> of the exception stack trace > */ > public static StringBuilder convert(final StringBuilder newStringBuilder, > final StackTraceElement[] stack) { > StringBuilder result = newStringBuilder; > if (stack != null && stack.length > 0) { > if (result == null) { > result = new StringBuilder(); > } > result.append(stack[0]); > for (int i = 1; i < stack.length; i++) { > result.append('\n'); > result.append(stack[i]); > } > } else { > if (result == null) { > result = new StringBuilder(); > } > } > return result; > } > } > {code} -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa For more information on JIRA, see: http://www.atlassian.com/software/jira