Bending JAXB to the will of Scala [1/2]
case class EntryType(entrytypeoption: Seq[scalaxb.DataRecord[Any]] = Nil, | |
attributes: Map[String, scalaxb.DataRecord[Any]]) extends FeedTypeOption | |
case class EntryType(entrytypeoption: Seq[scalaxb.DataRecord[Any]] = Nil, | |
xmlbase: Option[java.net.URI] = None, | |
xmllang: Option[String] = None, | |
attributes: Map[String, scalaxb.DataRecord[Any]]) extends FeedTypeOption |
java.lang.NullPointerException | |
at com.sun.xml.internal.bind.v2.runtime.output.Encoded.setEscape(Encoded.java:96) | |
at com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput.doText(UTF8XmlOutput.java:306) | |
at com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput.text(UTF8XmlOutput.java:290) | |
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.leafElement(XMLSerializer.java:314) | |
at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$StringImplImpl.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:1037) | |
at com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$StringImplImpl.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:1016) | |
at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:241) | |
at com.sun.xml.internal.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:114) | |
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:343) | |
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:582) | |
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:325) | |
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:483) | |
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308) | |
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236) | |
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95) |
import scala.annotation.target.field | |
import javax.xml.bind.annotation._ | |
import javax.xml.bind.annotation.adapters._ | |
type xmlElement = XmlElement @field | |
type xmlTypeAdapter = XmlJavaTypeAdapter @field | |
class OptionAdapter[A](nones: A*) extends XmlAdapter[A, Option[A]] { | |
def marshal(v: Option[A]): A = v.getOrElse(nones(0)) | |
def unmarshal(v: A) = if (nones contains v) None else Some(v) | |
} | |
object Email { | |
class EmailOptionAdapter extends OptionAdapter[Email](null, Email("")) | |
} | |
@XmlAccessorType(XmlAccessType.FIELD) | |
case class Email(@xmlValue email:String) { | |
override def toString = email | |
private def this() = this("") | |
} | |
@XmlRootElement | |
@XmlAccessorType(XmlAccessType.FIELD) | |
case class Person(name:String, | |
@xmlTypeAdapter(classOf[Email.EmailOptionAdapter]) email:Option[Email] = None) { | |
private def this() = this("", None) | |
} |
java.lang.NullPointerException | |
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:54) | |
at sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38) | |
at java.lang.reflect.Field.get(Field.java:379) | |
at com.sun.xml.bind.v2.runtime.reflect.Accessor$FieldReflection.get(Accessor.java:266) | |
at com.sun.xml.bind.v2.runtime.reflect.Accessor.getUnadapted(Accessor.java:143) | |
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.hasValue(TransducedAccessor.java:251) | |
at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl$TransducerImpl.writeLeafElement(RuntimeClassInfoImpl.java:409) | |
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:256) | |
at com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:130) | |
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:361) | |
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593) | |
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:342) | |
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494) | |
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323) | |
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:251) | |
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95) |
import scala.annotation.target.field | |
import javax.xml.bind.annotation._ | |
import javax.xml.bind.annotation.adapters._ | |
import org.joda.time.DateTime | |
import org.joda.time.format.DateTimeFormatter | |
type xmlElement = XmlElement @field | |
type xmlTypeAdapter = XmlJavaTypeAdapter @field | |
/** | |
* NB The double type parameters ([S,A]) are necessary because MOXy always uses the first one as a target for casting | |
* from the input string before passing to unmarshal. Unfortunately this means you need to always pass String as | |
* the first type parameter when extending the CustomOptionAdapter (eg see DateTimeOptionAdapter). | |
* | |
* These bugs describe the behaviour and fix, | |
* - https://bugs.eclipse.org/bugs/show_bug.cgi?id=440681 | |
* - https://bugs.eclipse.org/bugs/show_bug.cgi?id=431803 | |
* The fix should be available in the next release after 2.5.2 | |
*/ | |
class CustomOptionAdapter[S,A](customAdapter:XmlAdapter[String,A], nones: String*) extends XmlAdapter[String, Option[A]] { | |
def marshal(v: Option[A]): String = { | |
v.map(customAdapter.marshal).getOrElse(nones(0)) | |
} | |
def unmarshal(v: String):Option[A] = { | |
if (nones contains v) None else Some(customAdapter.unmarshal(v)) | |
} | |
} | |
class DateTimeAdapter(dtf: DateTimeFormatter) extends XmlAdapter[String, DateTime] { | |
def unmarshal(v: String): DateTime = dtf.parseDateTime(v) | |
def marshal(v: DateTime): String = dtf.print(v) | |
} | |
class DateTimeOptionAdapter(dtf: DateTimeFormatter) extends CustomOptionAdapter[String, DateTime](new DateTimeAdapter(dtf), null, "") | |
@XmlRootElement | |
@XmlAccessorType(XmlAccessType.FIELD) | |
case class Entry(id:String | |
@xmlTypeAdapter(classOf[AtomDateTimeOptionAdapter]) published:Option[DateTime] = None { | |
private def this() = this("", None) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment