jaxb unable to create an instance of abstract class - java

#XmlSeeAlso({ Dog.class, Cat.class })
public abstract class Animal {}
#XmlRootElement(name="dog")
public class Dog extends Animal {}
#XmlRootElement(name="cat")
public class Cat extends Animal {}
#WebService(name = "WebServiceDemo", serviceName = "WebServiceDemo")
#SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL,
parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class WebServiceDemo {
#WebMethod
public String service(#WebParam(name = "animal") Animal animal) {
System.out.println("animal service calling.....");
return animal;
}
}
Now when i am calling this service method from client with Animal calss as a parameter that time i am getting error-
Caused by: javax.xml.bind.UnmarshalException: Unable to create an instance of Animal
- with linked exception:
[java.lang.InstantiationException]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:616)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:244)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:583)
at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:181)
at com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:73)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:455)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:433)
at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:71)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:137)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:240)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:277)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:246)
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:123)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:314)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:293)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:244)
at org.jboss.ws.core.jaxws.JAXBDeserializer.deserialize(JAXBDeserializer.java:71)

Abstract classes cannot be instantiated, that is the basic rule for them in Java. From the javadocs:
An abstract class is a class that is declared abstract—it may or may
not include abstract methods. Abstract classes cannot be instantiated,
but they can be subclassed.
Jaxb internally will try to unmarshall your xml to the java object. But if it is not able to create an object of Animal, how will it work. Hence it throws the exception. You need to provide a non-abstract class to JaxB to work.

Related

How to call method from a reference send to annotation in java

I have a Interface I and a Abstract Class A , I have My custom annotation MyAnnotation which should take parameter as subclass S of A, now while processing annotation I want to call method of concrete class S
public interface I{
void m1();
}
public abstract class A implements I {
public abstract void m1();
}
public #interface MyAnnotation {
public Class< ? extends A> ref();
public Class< ? super A> ref2();
}
public S extends A{
public void m1() {}
}
I am annotating method like
#MyAnnotation(ref= new XX() ) or #MyAnnotation(ref= XX.class )
#MyAnnotation(ref= new yy() ) or #MyAnnotation(ref= yy.class )
whichever works
//In spring aspect before processing I am getting method annotation and trying to call m1()
annotation.ref().m1() //Error
annotation.ref2().m1() //Error
You can't use new XX() in an annotation. Annotations parameters can use a very specific set of types:
primitive
String
Class
an Enum
another Annotation
an array of any of the above
See this answer.
So to accomplish what you're trying to accomplish, you'd have to use a class.
You would then have to use reflection to create an instance and invoke the method.
Class<?> clazz = annotation.ref();
I instance = (I) cls.getConstructor().newInstance();
instance.m1();
See this answer.
Your classes must all have no-argument constructors, else you'll only be able to instantiate some this way but not others (leading you to have to conditionally branch based on the class).
You can't do that simply like that. You need an instance of the class first.
If your A class is a Spring's bean, you can inject ApplicationContext and get the bean from there. Then you can call a method.
#Autowired
private ApplicationContext context;
void test(MyAnnotation annotation) {
A bean = context.getBean(annotation.ref());
bean.m1();
}

Calling particular child method from abstract class using custom annotation

I have a abstract class containing run() method and few children classes overriding run method with different implementation. There a custom annotation class also, each child class has this annotation with different value to distinguish each child class. I was to call this run method for each child class from abstract class object using these annotations without using child class name. Is it possible or there some other way to do this?
CODE IS HERE-------
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface CustomAnno {
public String name();
}
public abstract class AbstractClass {
abstract void run();
}
#CustomAnno(name="one")
public class ExtendingClassOne extends AbstractClass {
#Override
void run() {
System.out.println("class one extending");
}
}
#CustomAnno(name="two")
public class ExtendingClassTwo extends AbstractClass {
#Override
void run() {
System.out.println("class two extending");
}
}
So having abstract class and annotation values "one" and "two", can I call run method for each child class without using child class name.
We can use ClassPathScanningCandidateComponentProvider spring library to list all the classes that use a particular kind of annotation. Here annotations can be custom or default one. So putting annotations on all child classes that extend that abstract class can give list of only those child classes only. This solved my problem.

Can't get JAXB to handle interfaces with simple example

I'm trying the simple example for JAXB Interfaces shown at Unofficial JAXB Guide - Mapping interfaces — Project Kenai, section 3.2.1 and it won't work for me. I'm in latest JDK 1.8_70 and not using any special libraries. Code for completeness sake:
#XmlRootElement
class Zoo {
#XmlAnyElement
public List<Animal> animals;
}
interface Animal {
void sleep();
void eat();
...
}
#XmlRootElement
class Dog implements Animal { ... }
#XmlRootElement
class Lion implements Animal { ... }
Any help on this? The error I'm getting is:
[com.sun.istack.internal.SAXException2: class testjaxb.Cat nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class testjaxb.Cat nor any of its super class is known to this context.]
EDIT: Posted JAXBContext.newInstance code:
Zoo zoo = new Zoo();
zoo.animals = new ArrayList<Animal>();
zoo.animals.add( new Cat() );
zoo.animals.add( new Dog() );
zoo.animals.add( new Dog() );
JAXBContext ctx = JAXBContext.newInstance(Zoo.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.marshal(zoo, System.out);
Try specifying the other classes in the list you provide to JAXBContext.newInstance().
JAXBContext ctx = JAXBContext.newInstance(Zoo.class, Cat.class, Dog.class);
Applying the #XmlSeeAlso annotation to your Zoo class should also work.
#XmlRootElement
#XmlSeeAlso({Cat.class, Dog.class})
class Zoo {
...
}

Class Cast Exception Generics Reflection ParameterizedType

I have looked for an answer on Stack for a while. All the answers look like they say I already have the right answer, but I still keep getting a class cast exception for the first line in the constructor below.
SEVERE: Exception while loading the app : EJB Container initialization error
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at com.domain.security.logging.ElsAbstractCrudClass.<init>(ElsAbstractCrudClass.java:54)
Here's the code. After looking at the documentation I still can't figure it out. I'm relatively new to generics and reflection so need some help. TIA.
public abstract class ElsAbstractCrudClass<T> {
Class<T> entity;
public ElsAbstractCrudClass() {
[line 54] ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
Type type = genericSuperclass.getActualTypeArguments()[0];
this.entity = (Class<T>) type;
}
}
Here is a subclass of the abstract crud class (SessionLog is a JPA entity):
#Stateless
public class SessionLogger extends ElsAbstractCrudClass<SessionLog> {
#PersistenceContext(unitName = "ELS_Soulard_PU")
private EntityManager em;
#EJB
DozerInstantiator di;
//SessionLog entity;
//SessionLog sessionLog = new SessionLog();
static final Logger logger = Logger.getLogger(SessionLogger.class.getSimpleName());
public SessionLogger() {
}
...
getGenericSuperclass returns an instance of ParameterizedType if the super class is generic, and an instance of Class if it is not. Presumably you have something like:
class A extends B { ... }
class B extends ElsAbstractCrudClass<Person> { ... }
Now, getClass() return A.class with superclass B.class, which is not generic ...
You could generalize your code snippet to work as long as the runtime class is not generic (recursively walking the type hierarchy, replacing type parameters by their definitions as you go). However, unless you have dozens of crud classes, requiring the subclass to pass the proper class object is easier:
public abstract class ElsAbstractCrudClass<T> {
final Class<T> entityClass;
public ElsAbstractCrudClass(Class<T> entityClass) {
this.entityClass = entityClass;
}
}
You got this error because EJB Container extend your Stateless bean to wrap EJB specific logic on method invocation. So at deployment time you have somthing like this:
ContainerSubclass extends SessionLogger {}
Solutions:
1) In your constructor first call
... = getClass().getSuperClass();
...
2) or code against interfaces so EJB container would create Dynamic Proxy through reflection.
Another way to run into trouble is if your extending class uses the raw type, not the generic type. In other words, this subclass will generate your exception, because its supertype is simply the raw type ElsAbstractCrudClass.
public class EE extends ElsAbstractCrudClass { ... }
But this one will not because its supertype is the generic type ElsAbstractCrudClass
public class EE extends ElsAbstractCrudClass<String> { ... }

Using polymorphic JAX-WS webservice parameters

I have this simple JAX-WS WebService:
#WebService
public class AnimalFeedingService {
#WebMethod
public void feed(#WebParam(name = "animal") Animal animal) {
// Whatever
}
}
#XmlSeeAlso({ Dog.class, Cat.class })
public abstract class Animal {
private double weight;
private String name;
// Also getters and setters
}
public class Dog extends Animal {}
public class Cat extends Animal {}
I create a client and call feed with an instance of Dog.
Animal myDog = new Dog();
myDog .setName("Rambo");
myDog .setWeight(15);
feedingServicePort.feed(myDog);
The animal in the body of the SOAP call looks like this:
<animal>
<name>Rambo</name>
<weight>15</weight>
</animal>
and I get an UnmarshallException because Animal is abstract.
Is there a way to have Rambo unmarshalled as an instance of class Dog? What are my alternatives?
As you might have guessed, XML parser is not able to determine the exact subtype of animal you used when requesting because anything it sees is generic <animal> and a set of tags that are common to all types, hence the error. What JAX-WS implementation do you use? It is the responsibility of the client to properly wrap polymorphic types when sending request. In Apache CXF (I checked your code against newest 2.3.2 version) the SOAP request body looks like this:
<animal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:dog">
<name>Rambo</name>
<weight>15.0</weight>
</animal>
The xsi:type="ns2:dog" is crucial here. It seems like your JAX-WS client is sending incorrect request that confuses the server. Try sending this request with some other client, like SoapUI, to see whether your server reacts properly.
As I said, it works just fine with Spring/Apache CXF and exactly the same code you've provided, I only extracted Java interface to make CXF happy:
public interface AnimalFeedingService {
#WebMethod
void feed(#WebParam(name = "animal") Animal animal);
}
#WebService
#Service
public class AnimalFeedingServiceImpl implements AnimalFeedingService {
#Override
#WebMethod
public void feed(#WebParam(name = "animal") Animal animal) {
// Whatever
}
}
...and the server/client glue code:
<jaxws:endpoint implementor="#animalFeedingService" address="/animal"/>
<jaxws:client id="animalFeedingServiceClient"
serviceClass="com.blogspot.nurkiewicz.test.jaxws.AnimalFeedingService"
address="http://localhost:8080/test/animal">
</jaxws:client>

Categories

Resources