user1552879
user1552879

Reputation: 99

REST API with Interfaces - JAXB

I am using an implementation of an interface in Java. For eg: There can be many PaymentTypes like Credit Card, Mobile etc. I am making a REST API which contains an interface- how do I map this in JAXB, currently it gives me JAXBException occurred : 2 counts of IllegalAnnotationExceptions.

Currently I am using Apache-CXF and JAXb

@XmlRootElement
public class Payment {
    @XmlElement
    private PaymentType paymentType;
    @XmlElement
    private long price;

    public Payment() {
    }

    public Payment(final PaymentType paymentType, final long price) {
        super();
        this.paymentType = paymentType;
        this.price = price;
    }
}

@Path("/trial")
public class TrialService {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Payment> getPayments() {
        final List<Payment> payments = new LinkedList<Payment>();
        final CreditCardDetails creditCard = new CreditCardDetails(
                "8767798778", "123", 12, 2016);
        final Payment payment = new Payment(creditCard, 10);
        payments.add(payment);
        return payments;
    }
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public PaymentDetails startPayment(final PaymentDetails paymentDetails) {
    return paymentDetails;
}
}

public class CreditCardDetails implements PaymentType {

    @XmlElement
    private String creditCardNumber;
    @XmlElement
    private String cvv;
    @XmlElement
    private int expirationMonth;
    @XmlElement
    private int expirationYear;

    public CreditCardDetails() {
    }

    @SuppressWarnings("javadoc")
    public CreditCardDetails(
            // final BillingAddress billingAddress,
            final String creditCardNumber, final String cvv,
            final int expirationMonth, final int expirationYear) {
        super();
        this.creditCardNumber = creditCardNumber;
        this.cvv = cvv;
        setExpirationMonth(expirationMonth);
        setExpirationYear(expirationYear);
    }
}

How should I be mapping this or should I be using an entirely different approach?

Edits: For the POST method I am receiving a payment. Payment could contain any object CreditCard, Wallet etc. What annotation should I provide so that it is desirialized correctly. Currently it throws a JAXB exception.

Upvotes: 1

Views: 566

Answers (1)

swist
swist

Reputation: 1171

The full error message which you've got is:

Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions PaymentType is an interface, and JAXB can't handle interfaces.

You need to use concreate class for your elements or point it in type attribute of @XmlElement annotation:

@XmlElement(type = CreditCardDetails.class)
private PaymentType paymentType;

If you have more classes that uses PaymentType interface then you may use the following solution:

 @XmlAnyElement
 @XmlElementRefs({
    @XmlElementRef(type=CreditCardDetails.class),
    @XmlElementRef(type=Wallet.class)   
 })
 PaymentType paymentType;

The list of @XmlElementRefs can have any number of elements but all possibilities must be listed. CreditCardDetails and Wallet must be annotated with @XmlRootElement.

You can skip @XmlElementRefs annotation:

@XmlAnyElement(lax=true)
PaymentType paymentType;

but in that case make sure you have any required class in JAXB context, if you do not use registry annotate your class with PaymentType field with @XmlSeeAlso({CreditCardDetails.class, Wallet.class}).

Upvotes: 2

Related Questions