PowerMockito & x-stream: handle multi part e-mail #13

Closed
delgurth opened this Issue Jun 10, 2015 · 7 comments

Comments

Projects
None yet
2 participants
@delgurth

I'm trying to write a unit test for an e-mail service I'm working on. It uses an enum and I'm trying to extend that enum in order to see how the code deals with a new enum value.

I'm trying to use powermockito for it and this uses x-stream on the background. First I ran into an java 8 issue, that is fixed in 1.4.8, so I updated x-stream to 1.4.8 to get around that one. But now I'm running into something that I'm not able to fix with just a library upgrade. The debug information from xstream is:

com.thoughtworks.xstream.converters.ConversionException: Cannot construct class java.lang.Class, missing default constructor : javax.activation.ActivationDataFlavor.<init>()
---- Debugging information ----
message             : Cannot construct class java.lang.Class, missing default constructor
cause-exception     : java.lang.NoSuchMethodException
cause-message       : javax.activation.ActivationDataFlavor.<init>()
class               : javax.activation.ActivationDataFlavor
required-type       : javax.activation.ActivationDataFlavor
converter-type      : com.thoughtworks.xstream.converters.reflection.ExternalizableConverter
path                : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/next/next/fTarget/emailGateway/mailSender/mimeMessages/javax.mail.internet.MimeMessage/dh/object/parts/javax.mail.internet.MimeBodyPart/dh/object/parts/javax.mail.internet.MimeBodyPart/dh/dataContentHandler/dch/myDF
line number         : 6233
class[1]            : com.sun.mail.handlers.multipart_mixed
converter-type[1]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[2]            : javax.activation.ObjectDataContentHandler
class[3]            : javax.activation.DataHandler
class[4]            : javax.mail.internet.MimeBodyPart
class[5]            : java.util.Vector
converter-type[2]   : com.thoughtworks.xstream.converters.collections.CollectionConverter
class[6]            : javax.mail.internet.MimeMultipart
class[7]            : javax.mail.internet.MimeMessage
class[8]            : [Ljavax.mail.internet.MimeMessage;
converter-type[3]   : com.thoughtworks.xstream.converters.collections.ArrayConverter
class[9]            : com.delgurth.service.message.test.MockJavaMailSender
class[10]           : com.delgurth.service.message.SmtpEmailGateway
class[11]           : com.delgurth.service.message.SmtpEmailGatewayTest
class[12]           : org.junit.internal.runners.statements.InvokeMethod
class[13]           : org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks
class[14]           : org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks
class[15]           : org.powermock.modules.junit4.rule.PowerMockStatement
class[16]           : org.powermock.modules.junit4.rule.PowerMockStatement$1
version             : 1.4.8
-------------------------------
@joehni

This comment has been minimized.

Show comment
Hide comment
@joehni

joehni Jun 18, 2015

Member

Sorry for the delay, I was offline.

Hmm. The Java specification requires that an Externalizable type has a public default constructor (see Javadoc of Externalizable):

When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor, then the readExternal method called. Serializable objects are restored by reading them from an ObjectInputStream.

Funny, that Oracle does not follow its specification with ActivationDataFlavor. Actually you're the first one who unmarshals this type 😏 I'll investigate ...

Member

joehni commented Jun 18, 2015

Sorry for the delay, I was offline.

Hmm. The Java specification requires that an Externalizable type has a public default constructor (see Javadoc of Externalizable):

When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor, then the readExternal method called. Serializable objects are restored by reading them from an ObjectInputStream.

Funny, that Oracle does not follow its specification with ActivationDataFlavor. Actually you're the first one who unmarshals this type 😏 I'll investigate ...

@joehni joehni added the bug label Jun 18, 2015

@joehni

This comment has been minimized.

Show comment
Hide comment
@joehni

joehni Jun 18, 2015

Member

Even better: Java IO fails also to deserialize an ActivationDataFlavor too:

[snip]
Caused by: java.io.InvalidClassException: javax.activation.ActivationDataFlavor; no valid constructor
    at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
    at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at com.thoughtworks.acceptance.ExternalizableTest.deserialize(ExternalizableTest.java:242)
    ... 19 more
Member

joehni commented Jun 18, 2015

Even better: Java IO fails also to deserialize an ActivationDataFlavor too:

[snip]
Caused by: java.io.InvalidClassException: javax.activation.ActivationDataFlavor; no valid constructor
    at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
    at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at com.thoughtworks.acceptance.ExternalizableTest.deserialize(ExternalizableTest.java:242)
    ... 19 more
@delgurth

This comment has been minimized.

Show comment
Hide comment
@delgurth

delgurth Jun 19, 2015

Nice... Guess I should open a bug on the JDK then.

Nice... Guess I should open a bug on the JDK then.

@joehni joehni closed this in d3f8c22 Jun 23, 2015

joehni added a commit that referenced this issue Jun 23, 2015

@delgurth

This comment has been minimized.

Show comment
Hide comment
@delgurth

delgurth Jun 24, 2015

Thanks for the quick fix! I also raised a bug @ Oracle, but that will take some time since I'm not a paying customer. It's currently pending review, I'll update this issue with the actual bug as soon as it is accepted.

Thanks for the quick fix! I also raised a bug @ Oracle, but that will take some time since I'm not a paying customer. It's currently pending review, I'll update this issue with the actual bug as soon as it is accepted.

@delgurth

This comment has been minimized.

Show comment
Hide comment
@delgurth

delgurth Jun 24, 2015

I'm trying to use this snapshot version, but it seems that the security permissions added to 1.4.7 are enabled per default on 1.5.0-SNAPSHOT? Is there an easy / quick way to turn those off? Since now I'm getting a lot of com.thoughtworks.xstream.security.ForbiddenClassException

I'm trying to use this snapshot version, but it seems that the security permissions added to 1.4.7 are enabled per default on 1.5.0-SNAPSHOT? Is there an easy / quick way to turn those off? Since now I'm getting a lot of com.thoughtworks.xstream.security.ForbiddenClassException

@joehni

This comment has been minimized.

Show comment
Hide comment
@joehni

joehni Jun 24, 2015

Member

You should activate the security stuff also for 1.4.x. I am able to feed an XML into XStream wiping your hard disk (depends on the access rights of the Java process though). See http://x-stream.github.io/security.html and use a WildcardTypePermission for your types in production or an AnyTypePermission for tests without any limit.

Member

joehni commented Jun 24, 2015

You should activate the security stuff also for 1.4.x. I am able to feed an XML into XStream wiping your hard disk (depends on the access rights of the Java process though). See http://x-stream.github.io/security.html and use a WildcardTypePermission for your types in production or an AnyTypePermission for tests without any limit.

@delgurth

This comment has been minimized.

Show comment
Hide comment
@delgurth

delgurth Jan 27, 2016

I said I would update this issue as soon as the bug was accepted... Unfortunately I didn't see the feedback from Oracle (or I didn't get it at all) when they accepted the bug, but here it is:

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8139190

Now I need to find how I get them to fix it. Guess I should submit the patch myself.

There is one other case that is not following the "spec" from Externalizable: https://docs.oracle.com/javase/8/docs/api/javax/management/loading/PrivateMLet.html

I said I would update this issue as soon as the bug was accepted... Unfortunately I didn't see the feedback from Oracle (or I didn't get it at all) when they accepted the bug, but here it is:

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8139190

Now I need to find how I get them to fix it. Guess I should submit the patch myself.

There is one other case that is not following the "spec" from Externalizable: https://docs.oracle.com/javase/8/docs/api/javax/management/loading/PrivateMLet.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment