I have an xsd which conatins a entity Taddress having a property country_code which has enum type. I am uanble to marshal the xml out of the root entity because it throws an exception as below
javax.xml.bind.MarshalException
- with linked exception: [Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.XMLMarshalException Exception
Description: An error occurred marshalling the object Internal
Exception: Exception [EclipseLink-115] (Eclipse Persistence Services -
2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: No conversion value provided for the attribute [CO].
Mapping:
org.eclipse.persistence.oxm.mappings.XMLDirectMapping[countryCode-->country_code/text()]
Descriptor: XMLDescriptor(generated.TAddress --> [])] at
org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:403)
at
com.crrinfra.dynamicOutputgen.utils.HelloWorld.generateTransaction(HelloWorld.java:52)
at
com.crrinfra.dynamicOutputgen.utils.XMLUtilities.generateJaxBContext(XMLUtilities.java:259)
at
com.crrinfra.dynamicOutputgen.utils.DynamicXSDLoader.populateCache(DynamicXSDLoader.java:48)
at
com..crrinfra.dynamicOutputgen.DynamicOutputXSDParser.main(DynamicOutputXSDParser.java:16)
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services
- 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException Exception
Description: An error occurred marshalling the object Internal
Exception: Exception [EclipseLink-115] (Eclipse Persistence Services -
2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: No conversion value provided for the attribute [CO].
Mapping:
org.eclipse.persistence.oxm.mappings.XMLDirectMapping[countryCode-->country_code/text()]
Descriptor: XMLDescriptor(generated.TAddress --> []) at
org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:97)
at
org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:911)
at
org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:848)
at
org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:401)
... 4 more
public class HelloWorld {
public static void generateTransaction(DynamicJAXBContext jaxbContext) throws JAXBException, NoSuchFieldException, SecurityException{
DynamicEntity entity = jaxbContext.newDynamicEntity("generated.Report");
DynamicType type = jaxbContext.getDynamicType("generated.Report");
DynamicEntity childEntity3 = jaxbContext.newDynamicEntity("generated.TAddress");
DynamicType type1 = jaxbContext.getDynamicType("generated.TAddress");
childEntity3.set("addressType", "M");
childEntity3.set("address", "XXXX");
childEntity3.set("town", "XXX");
childEntity3.set("city", "XXXXX");
childEntity3.set("zip", "751006");
childEntity3.set("countryCode", "CO");
childEntity3.set("state", "OD");
childEntity3.set("comments", "Permanent Address");
entity.set("location", childEntity3);
XMLDirectMapping enumMappings = (XMLDirectMapping) ((DynamicTypeImpl) type1).getMapping("countryCode");
System.out.println(enumMappings.isDirectToFieldMapping());
JAXBMarshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(entity, System.out);
}
}
Please advise on how to set the property. I have uploaded the xsd with this question
I have found the answer to my question and hence thought of closing this thread. I would be happy to receive feedback on this approach
public class EnumAttributeHandler implements IAttributeHandler {
DynamicTypeImpl typeAttr;
public EnumAttributeHandler(DynamicTypeImpl typeAttr) {
// TODO Auto-generated constructor stub
this.typeAttr=typeAttr;
}
#Override
public DynamicEntity attributeSetter(CRROutputAttributePojo attrPojo, DynamicEntity currentEntitytag, HashMap<String, Object> params,String setterValue) throws CRROutputGenException {
// TODO Auto-generated method stub
XMLDirectMapping enumMappings = (XMLDirectMapping) (typeAttr)
.getMapping(attrPojo.getActualAttrName());
EnumTypeConverter converter=null;
if(enumMappings.getConverter() instanceof EnumTypeConverter)
converter = (EnumTypeConverter) enumMappings.getConverter();
else
throw new CRROutputGenException("Invalid type of converter");
try {
if (setterValue != null) {
Object enumField = ((DynamicJAXBContext) params.get("jaxbContext")).getEnumConstant(converter.getEnumClassName().toString(), setterValue);
currentEntitytag.set(attrPojo.getActualAttrName(), enumField);
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new CRROutputGenException(e.getMessage());
}
return currentEntitytag;
}
}
Related
I maintain a web application that have a page with the JSF tag <f:event. I have rewrote a method in a service class for it to throw a business exception. However, when the business exception is thrown, it isn't caught in managed bean and the exception is showed on the page. Seems that my code try/catch doesn't work.
In XHTML:
<f:event listener="#{resourceBean.init(enrollment)}" type="preRenderView" />
Listener method in Managed Bean:
private boolean canCreateResource;
public void init(Enrollment enrollment) {
(...)
try {
canCreateResource = resourceService.canCreateResource(enrollment);
} catch (BusinessException e) {
canCreateResource = false;
}
}
Method in service class:
public boolean canCreateResource(Enrollment enrollment) {
if (...) {
if (mandateService.isCoordinator(user, course)) {
return true;
} else {
throw new BusinessException("Undefined business rule.");
}
}
return false;
}
From what I read on other sites, I suppose I have to implement some JSF's handler class. But which and how?
EDITED
OBS 1: The BusinessException class extends RuntimeException class.
OBS 2: The attribute canCreateResource was created to control the render of a button.
It's because you threw a RuntimeException from an EJB.
When such RuntimeException is not annotated with #ApplicationException, then the EJB container will wrap it in an javax.ejb.EJBException and rethrow it. This is done so because runtime exceptions are usually only used to indicate bugs in code logic, i.e. programmer's mistakes and not enduser's mistakes. You know, NullPointerException, IllegalArgumentException, IndexOutOfBoundsException, NumberFormatException and friends. This allows the EJB client to have one catch-all point for such runtime exceptions, like catch (EJBException e) { There's a bug in the service layer or in the way how we are using it! }
If you had tried catch (Exception e) and inspected the actual exception, then you'd have noticed that.
Fix your BusinessException class accordingly to add that annotation, it will then be recognized as a real application exception and not be wrapped in an EJBException:
#ApplicationException(rollback=true)
public class BusinessException extends RuntimeException {
// ...
}
Do note that in case you throw an non-RuntimeException, then you still need to keep the annotation on that, explicitly with rollback=true, because by default it wouldn't perform a rollback, on the contrary to a RuntimeException without the annotation.
#ApplicationException(rollback=true)
public class BusinessException extends Exception {
// ...
}
Summarized:
RuntimeException thrown from transactional EJB method will perform full rollback, but exception will be wrapped in EJBException.
RuntimeException with #ApplicationException from transactional EJB method will only perform full rollback when rollback=true is explicitly set.
Exception from transactional EJB method will not perform full rollback.
Exception with #ApplicationException from transactional EJB method will only perform full rollback when rollback=true is explicitly set.
Note that #ApplicationException is inherited over all subclasses of the custom exception, so you don't need to repeat it over all of them. Best would be to have it as an abstract class. See also the examples in the related question linked below.
See also:
Letting the presentation layer (JSF) handle business exceptions from service layer (EJB)
If isCoordinator method can eventually throw an exception you should add a try catch block inside canCreateResource method. You can throw your own exception or propagate the original one. In both cases you have to declare it in the method signature. If you throw BusinessException:
public void canCreateResource(Enrollment enrollment) throws BusinessException
Do not return any value. Or return a boolean value but do not throw any exception.
In the catch block inside the init method add the Facelet message exception:
...
} catch (BusinessException e) {
this.canCreateResource = false;
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), ""));
}
}
Also in your page you have to add <h:messages> tag.
In case you want to catch an exception that you did not create yourself (and you are not able to annotate with #ApplicationException), you can catch all exceptions and see if one of the causes is of the type you want to catch.
You can check the causes of the exception recursively:
public static <T extends Throwable> T getCauseOfType(final Throwable throwable,
final Class<T> type) {
if (throwable == null) {
return null;
}
return type.isInstance(throwable) ? (T) throwable : getCauseOfType(throwable.getCause(), type);
}
public static <T extends Throwable> boolean hasCauseOfType(final Throwable throwable,
final Class<T> type) {
return getCauseOfType(throwable, type) != null;
}
You can use this like:
try {
...
}
catch (Exception e) {
if (hasCauseOfType(e, SomeException.class)) {
// Special handling
}
else {
throw e;
}
}
The EJB method (using CMT) that updates an entity supplied :
#Override
#SuppressWarnings("unchecked")
public boolean update(Entity entity) throws OptimisticLockException {
// Code to merge the entity.
return true;
}
This will throw the javax.persistence.OptimisticLockException, if concurrent update is detected which is to be handled precisely by the caller (a managed bean).
public void onRowEdit(RowEditEvent event) {
try {
service.update((Entity) event.getObject())
} catch(OptimisticLockException e) {
// Add a user-friendly faces message.
}
}
But doing so makes an additional dependency from the javax.persistence API on the presentation layer compulsory which is a design smell leading to tight-coupling.
In which exception should it be wrapped so that the tight-coupling issue can be omitted in its entirely? Or is there a standard way to handle this exception which in turn does not cause any service layer dependencies to be enforced on the presentation layer?
By the way, I found it clumsy to catch this exception in the EJB (on the service layer itself) and then return a flag value to the client (JSF).
Create a custom service layer specific runtime exception which is annotated with #ApplicationException with rollback=true.
#ApplicationException(rollback=true)
public abstract class ServiceException extends RuntimeException {}
Create some concrete subclasses for general business exceptions, such as constraint violation, required entity, and of course optimistic lock.
public class DuplicateEntityException extends ServiceException {}
public class EntityNotFoundException extends ServiceException {}
public class EntityAlreadyModifiedException extends ServiceException {}
Some of them can be thrown directly.
public void register(User user) {
if (findByEmail(user.getEmail()) != null) {
throw new DuplicateEntityException();
}
// ...
}
public void addToOrder(OrderItem item, Long orderId) {
Order order = orderService.getById(orderId);
if (order == null) {
throw new EntityNotFoundException();
}
// ...
}
Some of them need a global interceptor.
#Interceptor
public class ExceptionInterceptor implements Serializable {
#AroundInvoke
public Object handle(InvocationContext context) throws Exception {
try {
return context.proceed();
}
catch (javax.persistence.EntityNotFoundException e) { // Can be thrown by Query#getSingleResult().
throw new EntityNotFoundException(e);
}
catch (OptimisticLockException e) {
throw new EntityAlreadyModifiedException(e);
}
}
}
Which is registered as default interceptor (on all EJBs) as below in ejb-jar.xml.
<interceptors>
<interceptor>
<interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
As a general hint, in JSF you can also have a global exception handler which just adds a faces message. When starting with this kickoff example, you could do something like this in YourExceptionHandler#handle() method:
if (exception instanceof EntityAlreadyModifiedException) { // Unwrap if necessary.
// Add FATAL faces message and return.
}
else {
// Continue as usual.
}
public class TestValidatorSample {
public static void main(String aa[]) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder parser = dbf.newDocumentBuilder();
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// /test_elements.xsd
Schema schema = factory.newSchema(new StreamSource(TestValidatorSample.class.getResource(
"/xsds/pakagename/test_elements.xsd").toString()));
Validator validator = schema.newValidator();
DOMSource domsrc = new DOMSource(parser.parse(new InputSource("test-example.xml")));
try {
validator.validate(domsrc);
System.out.println("Validation successfull!!!");
// System.out.println(xmlFile.getSystemId() + " is valid");
} catch (SAXException e) {
System.out.println("Validation not successfull!!!");
// System.out.println(xmlFile.getSystemId() + " is NOT valid");
System.out.println("Reason: " + e.getLocalizedMessage());
}
}
}
Exception in thread "main" java.lang.NullPointerException at line 47.
I am getting a nullpointer(as mentioned above) exception while loading a schema.
In the above code snippet I am trying to load a schema which will be used to validate xmls generated in my application .
Can anybody please help me to find out why I am getting null pointer exception ?
I haven't been able to find a way to force a JAXBException when marshalling for a JUnit test. Does anyone have any ideas?
Here is my marshalling code:
public String toXml() {
log.debug("Entered toXml method");
String result = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
jaxbMarshaller.marshal(this, writer);
result = writer.toString();
} catch (JAXBException e) {
log.error(e);
}
log.debug("Exiting toXml method");
return result;
}
There are different ways to create a JAXBException during a marshal operation:
1 - Marshal an Invalid Object
You can generate a JAXBException during a marshal operation by marshalling an instance of a class that the JAXBContext isn't aware of (i.e. Take your example and use it to marshal an instance of Foo). This will produce the following exception.
Exception in thread "main" javax.xml.bind.JAXBException: class forum13389277.Foo nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:482)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
2 - Marshal to Invalid Output
If you try to marshal to an invalid output such as an OutputStream that has been closed:
FileOutputStream closedStream = new FileOutputStream("src/foo.xml");
closedStream.close();
jaxbMarshaller.marshal(this, closedStream);
Then you will get a MarshalException which is a subclass of JAXBException.
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[java.io.IOException: Stream Closed]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:320)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
Caused by: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:318)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.flushBuffer(UTF8XmlOutput.java:413)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.endDocument(UTF8XmlOutput.java:137)
at com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput.endDocument(IndentingUTF8XmlOutput.java:165)
at com.sun.xml.bind.v2.runtime.XMLSerializer.endDocument(XMLSerializer.java:852)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.postwrite(MarshallerImpl.java:369)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:316)
... 3 more
I'm trying to use the ServiceExceptionHandler on my Serivce which extends RestServiceBase<TViewModel>
I can use the AppHost.ServiceExceptionHandler, that's working fine. I need the user info from the HttpRequest, thats not available at AppHost level.
So I'm trying to use the ServiceExceptionHandler on Service level. Though I set the delegate on service ctor, it's null when exception thrown on OnGet method
public class StudentService : RestServiceBase<Student>
{
public StudentService()
{
ServiceExceptionHandler = (request, exception) =>
{
logger.Error(string.Format("{0} - {1} \n Request : {2}\n", HttpRequest.UserName(), exception.Message, request.Dump()), exception);
var errors = new ValidationErrorField[] { new ValidationErrorField("System Error", "TODO", "System Error") };
return DtoUtils.CreateErrorResponse("System Error", "System Error", errors);
};
}
}
I'm not sure of what is the issue with this code. Any help will be appreciated.
Register Global AppHost.ServiceExceptionHandler
In your AppHost.Configure() you can register a global Exception handler with:
this.ServiceExceptionHandler = (request, ex) => {
... //handle exception and generate your own ErrorResponse
};
For finer-grained Exception handlers you can override the following custom service event hooks:
Handling Exceptions with the New API
If you're using the New API you can override the Exception by providing a custom runner, e.g:
public class AppHost {
...
public virtual IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
//Cached per Service Action
return new ServiceRunner<TRequest>(this, actionContext);
}
}
public class MyServiceRunner<T> : ServiceRunner<T> {
public override object HandleException(
IRequestContext requestContext, TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}
Handling Exceptions with the Old API
RestServiceBase<T> is uses the old API in which you can handle errors by overriding the HandleException method, e.g:
public class StudentService : RestServiceBase<Student>
{
...
protected override object HandleException(T request, Exception ex)
{
LogException(ex);
return base.HandleException(request, ex);
}
}