How is StringWriter taking taking new value? - jaxb

Can someone please explain to me how writer.toString would hold the customer data? It appears as though marshal(customer,writer) somehow modified the writer. Please see below, thanks:
Customer customer = new Customer();
customer.setId(42);
customer.setName("Bill Burke");
JAXBContext ctx = JAXBContext.newInstance(Customer.class);
StringWriter writer = new StringWriter();
ctx.createMarshaller().marshal(customer, writer);
[See here:]
String custString = writer.toString(); // how did writer suddenly take on value?
customer = (Customer)ctx.createUnmarshaller()
.unmarshal(new StringReader(custString));

StringWriter is a Writer-implementation that writes into a StringBuffer. When you call write(), you append to that StringBuffer. ToString() calls toString() on that StringBuffer and returns it.
Marshaller.marshal() just serializes the JAXB objects into XML, and writes them into the Writer (and thus into the StringBuffer). The StringReader in your second snippet then reads from the String created by StringBuffer.

I'm guessing that the reason writer is able to write the content is because the marshaller must have called a method inside the write object which changed whatever write points to. Therefore, after the marshal(), the writer references new data.
http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html (see bottom)

Related

NodaTime UnparsableValueException due to usage of "Z" in pattern

I am exchanging JSON messages between Java and C# (and vice-versa).
In Java I use a java.time.Instant (JSR-310) to represent a point in time on the global timeline. In order to create a human readable date/time string in JSON, I convert my Instant as follows:
private static final DateTimeFormatter FORMATTER = ofPattern("yyyy-MM-dd'T'HH:mm:ssZ").withZone(ZoneId.systemDefault());
which generates the following output:
2017-04-28T19:54:44-0500
Now, on the message consumer side of things (C#) I wrote a custom Newtonsoft.Json.JsonConverter, which extends the abstract JsonCreationConvert class that contains the following overridden ReadJson() method:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
if (reader.TokenType == JsonToken.StartArray)
{
return JToken.Load(reader).ToObject<string[]>();
}
reader.DateParseHandling = DateParseHandling.None; // read NodaTime string Instant as is
serializer.Converters.Add(NodaConverters.InstantConverter);
// Load JObject from stream
var jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
var writer = new StringWriter();
serializer.Serialize(writer, jObject);
using (var newReader = new JsonTextReader(new StringReader(writer.ToString())))
{
newReader.Culture = reader.Culture;
newReader.DateParseHandling = reader.DateParseHandling;
newReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
newReader.FloatParseHandling = reader.FloatParseHandling;
serializer.Populate(newReader, target);
}
return target;
}
Create() is an abstract method.
When I now convert this JSON string into a NodaTime.Instant (v2.0.0) by calling:
InstantPattern.General.Parse(creationTime).Value;
I get this exception:
NodaTime.Text.UnparsableValueException: The value string does not match a quoted string in the pattern. Value being parsed: '2017-04-28T19:54:44^-0500'. (^ indicates error position.)
If I pass a text literal "Z" (so no outputted offset "-0500" and Z is interpreted as 0 offset) the NodaTime.Serialization.JsonNet.NodaConverters.InstantConverter correctly reads without throwing an exception.
Looking into the GeneralPatternImpl I see:
internal static readonly InstantPattern GeneralPatternImpl = InstantPattern.CreateWithInvariantCulture("uuuu-MM-ddTHH:mm:ss'Z'");
Why does an InstantConverter require the offset to be a text literal? Is this happening because an Instant is agnostic to an offset? If this is the case, then why doesn't the InstantConverter just ignore the offset instead of throwing an exception? Do I need to write a custom converter to get around this problem?
That's like asking for 2017-04-28T19:54:44 to be parsed as a LocalDate - there's extra information that we'd silently be dropping. Fundamentally, your conversion from Instant to String in Java is "adding" information which isn't really present in the original instant. What you're ending up with is really an OffsetDateTime, not an Instant - it has more information than an Instant does.
You should decide what information you really care about. If you only care about the instant in time, then change your Java serialization to use UTC, and it should end up with Z in the serialized form, and all will be well. This is what I suggest you do - propagating irrelevant information is misleading, IMO.
If you actually care about the offset in the system default time zone, which your call to .withZone(ZoneId.systemDefault()) implies you do, then you should parse it as an OffsetDateTime on the .NET side of things. You can convert that to an Instant afterwards if you want to (just call ToInstant()).

JAXB Marshalling an Object truncates the result string if too many items in object

I currently have this:
JAXBContext jaxbContext = JAXBContext.newInstance(javaObject.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter stringWriter = new StringWriter();
jaxbMarshaller.marshal(javaObject, stringWriter);
String xml = stringWriter.toString();
The object contains a list of data_objects. As long as that list of data_objects is under 17 items I get a complete xml response. Once I have more than that the xml gets truncated. It does not throw an error. The xml string just has '...' at the end
<DataDetailObject xmlns:xsi="...
If I use System.Out instead of stringWriter I see the entire xml transformation correctly. What am I missing? Should I be using a different output for the marshalling?
The ... may be the behaviour of the debugger or viewer that you are using to introspect the String. If you write it to System.out you should see everything working correctly.

jetty continuation and unexplainable memory usage pattern

I have been struggling with something that looks very basic, the problem is related to use of Jetty continuations for long poll.
For the sake of simplicity, i have removed all my application specific code and just left simple continuation related code.
I am pasting the doPost method of my servlet below. The key question, where i need some expert guidance is
In the code block below, if i run it as is and fire post requests which carry a post body of approx 200 bytes then the amount of memory for 500 long poll connections is around 20 MB.
Where as if I comment the block highlighted as "decrease memory footprint :: comment block below" then the memory foot print comes down to 7 MB
In both the cases i wait for system to be stable, call GC multiple times and then take memory reading via jConsole. Its not exact, but the difference is so much and explanable that precision of few 100 bytes here or there does not matter.
My problem explodes, considering my server is required to hold 100K connections if not more. And here and this unexplanable increase in size eventually leads to close to GBs of extra heap used.
( what is causing this extra heap usage, when even what is read from the stream is not preserved outside the scope of doPost method. But still it adds to the heap....what am i missing?)
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Continuation cc = ContinuationSupport.getContinuation(req);
//if continuation is resumed, then send an answer back with
//hardcoded answer
if (cc.isResumed()) {
String myJson = "{\"1\",\"2\"}";
res.setContentType("application/json");
res.setContentLength(myJson.length());
PrintWriter writer = res.getWriter();
writer.write(myJson);
writer.close();
}
// if it is the first call to doPost ( not reentrant call )
else if (cc.isInitial()) {
//START :: decrease memory footprint :: comment this block :: START
// store the json from the request body in a string
StringBuffer jsonString = new StringBuffer();
String line = null;
BufferedReader bufferedReader = req.getReader();
while ((line = bufferedReader.readLine()) != null) {
jsonString.append(line);
}
//here jsonString was parsed and some values extracted
//though that code is removed for the sake of this publish
// as problem exists irrespective...of any processing
line = null;
bufferedReader.close();
bufferedReader = null;
jsonString = null;
// END :: decrease memory footprint :: comment this block :: END
cc.setTimeout(150000);
cc.suspend();
}
}
what is causing this extra heap usage...
Take a look at this line:
BufferedReader bufferedReader = req.getReader();
Note that you are not actually creating a new BufferedReader. When you call getBufferedReader, Jetty creates a BufferedReader which wraps an InputStreamReader which wraps a custom InputStream implementation which wraps a byte buffer. I am pretty sure that by executing the code which reads the entire message, you create large byte buffer inside the request object which stores the entire contents of the message body. Plus the request object maintains a reference to the readers.
At the beginning of the function you called:
Continuation cc = ContinuationSupport.getContinuation(req);
I believe your continuation is holding onto the request which is storing all the data. So the simple act of reading the data is allocating the memory which will be preserved until you discontinue your continuation.
One thing you might try just as an experiment. Change your code to:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(req.getInputStream()));
This way Jetty won't allocate it's own readers. Again - I don't know how much data is really stored in the readers compared to the rest of the request object - but it might help a little.
[update]
Another alternative is to avoid the problem. That's what I did (although I was using servlet 3.0 rather than Continuations). I had a resource - let's call it /transfer which would POST some data, then use an AsyncContext to wait for a response. I changed it to two requests with different URLS - /push and /pull. Any time I had some content that needed to be sent from client to server, it would go in the /push request which would then immediately return without creating an AsyncContext. Thus, any storage in the request is freed up right away. Then to wait for the response, I sent a second GET request with no message body. Sure - the request hangs around for a while - but who cares - it does not have any content.
You may have to rethink your problem and determine if you can perform your task in pieces - multiple requests - or whether you really have to handle everything in a single request.

object reference after Serialization and De-Serialization

Why after De-Serialization the object reference not same as it was before serilization.
ok let me Explain this
I am Having a String
string test = "TestString";
Now I do Serilization
DataContractJsonSerializer _DataContractJsonSerializer
= new DataContractJsonSerializer(typeof(string));
MemoryStream ms = new MemoryStream();
_DataContractJsonSerializer.WriteObject(ms, test);
var jsonString = Encoding.Default.GetString(ms.ToArray());
Now I do DeSerilization from jsonstring into actual value
MemoryStream ms1 =
new MemoryStream(Encoding.Unicode.GetBytes(jsonString));
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(string));
string DeseriliaedStrring = serializer.ReadObject(ms1) as string;
here in DeseriliaedStrring i got the actual value but if i check there reference they are not equal
bool isReferenceEqual = object.ReferenceEquals(DeseriliaedStrring, test);
Serialization creates copies of the object's values. Deserialization creates a completely new instance with the copied values.
Edit in response to your comment below: Deserialization doesn't call a constructor. If this is a problem, then override with ISerializable. This will serialise based on a call to ISerializable.GetObjectData and then call a particular constructor with SerializationInfo and StreamingContext fields.
When you serialize and deserialize an object, the deserialization will create an instance base on the serialized data. This is of course not the same instance as the original one, that seems fairly logical. After all, you have the following process:
You have an object instance
You create a string instance that is a representation of that object instance
You create an object instance based on the serialized data in the string
If you take into consideration that the original instance might have mutated, that the deserialization can happen in another process, even in another machine, it becomes quite clear that deserialization could not possibly return the original instance.
In this particular case, when the object is a String, you could imagine that the string interning would make the system reuse the old instance (if the deserialization happened within the same AppDomain). But that would probably* require DataContractJsonSerializer to be aware of this, which would make it unnecessarily complex.
*) I am actually not quite sure of exactly what part of the system that takes care of string interning.

JAXB: Unmarshal a message using QName?

How can I unmarshal a message that was marshalled using a QName local part different then what is expected?
My example is below:
Given an object to unmarshal that has been created using a marshal method such as
marshaller.marshal( new JAXBElement(
new QName("urn:somenamespace","DifferentNameMessage"),
OriginalMessageType.class,
originalMsg),
result);
(As I understand this code snippet, the QName is indicating to make the root element use a substitue name tag other than what is specified
in the original schema. Essentially using a substitute name method. For instance, in the QName above the original
tag would have been "NameMessage" but the message was marshalled using local part "DifferentNameMessage".)
I would normally use a method of unmarshalling such as:
String xmlString = convertStreamToString(in);
final StringReader xmlReader = new StringReader(xmlString);
final StreamSource xmlSource = new StreamSource(xmlReader);
JAXBContext jaxbContext = JAXBContext.newInstance(OriginalMessageType.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement ret = null;
ret = unmarshaller.unmarshal(xmlSource, OriginalMessageType.class);
But, if I use this method then the JAXBElement ret name is for the QName that was use to marshalled it, yet the DeclaredType is for
OriginalMessageType.class and the unmarshalled message contains null element values for the expected sub-elements, even though
the original message contains valid values for these sub-elements.
i am wondering if it is possible to specifiy the substitute QName during unmarshalling to indicate that it is a substitute and then to use the original tag in its place?
The following is correct:
ret = unmarshaller.unmarshal(xmlSource, OriginalMessageType.class);
Is this how you made your JAXBContext when your marshalled?
JAXBContext jaxbContext = JAXBContext.newInstance(OriginalMessageType.class);
Things to try:
Did you verify the marshalled document is correct?
What happens when you use the same JAXBContext for both marshal and unmarshal?

Resources