XStream OutOfMemoryError when generating xml - out-of-memory

I have a class defined to store configuration data for my application. I want to save the instances of this out to xml and use XStream for this. But I keep getting outofmemory errors when I try to write an instance.
Here is my class definition:
public class Eol_Target_Variable {
String name;
String alias;
long value;
long default_val;
int size;
int scaling;
int div;
Boolean read_access;
Boolean write_access;
public Eol_Target_Variable(String arg_name, String arg_alias, int arg_value, int arg_size, int arg_scaling,int arg_div)
{
name = arg_name;
alias = arg_alias;
value = arg_value;
default_val = 0;
scaling = arg_scaling;
div = arg_div;
size = arg_size;
read_access = true;
write_access = true;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(String name) {
this.name = name;
}
...etc for all standard getters and setters
Here is my handler for exporting a single object to xml
public void importConfiguration() {
XStream xstream = new XStream(new DomDriver());
Eol_Target_Variable myvar = new Eol_Target_Variable("jamie", "xtracold", 1977, 16, 1, 1);
String myxml = xstream.toXML(myvar);
System.out.print(myxml);
}
Every time I get "Exception in thread "JavaFX Application Thread" java.lang.OutOfMemoryError: Java heap space" thrown. I cannot see why such a simple class would throw the out of memory error. I have managed to output simple String objects using XStream so the library is working, it is just this custom class that seems to cause problems.
I have also tried to increase the heap allocated at startup with the VM arguments -Xms512m -Xmx1024m but that makes no difference.
Thanks
Jamie

Here is the new class declaration
#XStreamAlias("targetVar")
public class Eol_Target_Variable {
String name;
String alias;
long value;
#XStreamAlias("default")
long default_val;
int size;
int scaling;
int div;
#XStreamOmitField
Node node;
#XStreamOmitField
Boolean read_access;
#XStreamOmitField
Boolean write_access;
public Eol_Target_Variable(String arg_name, String arg_alias, int arg_value, int arg_size, int arg_scaling,int arg_div, Node arg_node)
{
name = arg_name;
alias = arg_alias;
value = arg_value;
default_val = 0;
scaling = arg_scaling;
div = arg_div;
size = arg_size;
node = arg_node;
read_access = true;
write_access = true;
}
I also used a different parser as the basic DOMParser never handled the massive amount of data. When I changed to StaxDriver was at least able to see the streams of text in the debug output as XStream traversed the whole scene graph.
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(Eol_Target_Variable.class);
I don't pretend to fully understand why declaring the class inlined causes problems, but I can reason as to why asking XStream to parse a complete Node might cause issues.
If anyone has any experience with XStream and complex data structures, that are declared inside a JavaFX app I would welcome their input.

Related

How to serialize a map that contains Image objects?

I'm creating an image gallery, which contains photo albums and each album contains pictures. These items are stored in a HashMap like this
HashMap<Album, ArrayList<Picture>> albums=new HashMap<>();
the problem starts when trying to serialize the map, because every Picture object contains an Image Object, so I can pick this Image and create an ImageView more easily for my app, the Picture constructor looks like this:
public Picture(String name,String place, String description, Image image)
I always get this exception:
java.io.NotSerializableException: javafx.scene.image.Image
Is there any way to make my Pictures serializable?
You need to customize the serialization of Picture. To customize serialization of an object you use the following two methods:
void readObject(ObjectInputStream) throws ClassNotFoundException, IOException
void writeObject(ObjectOutputStream) throws IOException
These methods can have any access modifier but are typically(?) private.
If you have the following class:
public class Picture implements Serializable {
private final String name;
private final String place;
private final String description;
private transient Image image;
public Picture(String name, String place, String description, Image image) {
this.name = name;
this.place = place;
this.description = description;
this.image = image;
}
public String getName() {
return name;
}
public String getPlace() {
return place;
}
public String getDescription() {
return description;
}
public Image getImage() {
return image;
}
}
You have at least three options regarding the serialization of the Image.
Serialize the location of the image.
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
String url = (String) in.readObject();
if (url != null) {
image = new Image(url);
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObjet();
out.writeObject(image == null ? null : image.getUrl());
}
The Image#getUrl() method was added in JavaFX 9.
Serialize the pixel data of the Image via the PixelReader. When deserializing you'll use a PixelWriter.
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
if (in.readBoolean()) {
int w = in.readInt();
int h = in.readInt();
byte[] b = new byte[w * h * 4];
in.readFully(b);
WritableImage wImage = new WritableImage(w, h);
wImage.getPixelWriter().setPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
image = wImage;
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeBoolean(image != null);
if (image != null) {
int w = (int) image.getWidth();
int h = (int) image.getHeight();
byte[] b = new byte[w * h * 4];
image.getPixelReader().getPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
out.writeInt(w);
out.writeInt(h);
out.write(b);
}
}
WARNING: Serializing the pixel data in this way is saving the image in an uncompressed format. Images can be quite large which may cause problems for you when using this approach.
This is dependent on the PixelReader being available, which is not always the case. If you read the documentation of Image#getPixelReader() you'll see (emphasis mine):
This method returns a PixelReader that provides access to read the pixels of the image, if the image is readable. If this method returns null then this image does not support reading at this time. This method will return null if the image is being loaded from a source and is still incomplete {the progress is still <1.0) or if there was an error. This method may also return null for some images in a format that is not supported for reading and writing pixels to.
Outside still-loading and errors, some non-exhaustive testing indicates animated GIFs do not have an associated PixelReader.
Serialize the actual image file (I don't recommend this one, reasons below).
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
if (in.readBoolean()) {
byte[] bytes = new byte[in.readInt()];
in.readFully(bytes);
image = new Image(new ByteArrayInputStream(bytes));
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeBoolean(image != null);
if (image != null) {
byte[] bytes;
try (InputStream is = new URL(image.getUrl()).openStream()) {
bytes = is.readAllBytes();
}
out.writeInt(bytes.length);
out.write(bytes);
}
}
This assumes the Image wasn't loaded from a resource (or at least that the URL has a scheme).
However, as I said I don't recommend this approach. For one, it only allows you to serialize the Picture instance one time because the original URL is lost after deserialization. You could get around this by storing the location separately but then you might as well use option #1. Then there's also the fact you open up an InputStream and read from it during serialization; this could be quite unexpected behavior for a developer serializing Picture instances.
Some notes:
There may be room for optimizations in the code above.
Options #1 and #3 don't take the requested width and height of the image into account. This may lead to having a larger image in memory after deserialization. You can modify the code to fix this.
Your Picture class seems like a model class. If that's the case, it may be better to simply store the location of the image in a field rather than the Image itself (this can also make customizing the serialization unneeded); then have other code responsible for loading the actual Image (e.g. a cache) based on the location stored in Picture. Either that or allow for lazily loading the Image in the Picture instance.
The point is to avoid loading Images when you don't need them. For instance, what if part of your UI only wants to display a list of available pictures by name. If you have thousands of Pictures you'll want to avoid loading thousands of Images as you could very easily run out of memory (at even just a few dozen images).

Why isn't this Math.random method working?

Since Java doesn't allow to return two types in one method, I thought best way to do it is to use get methods.
Simply, I wanted computer to generate two random numbers, and if they were not the same I wanted it to print sum of them. If they were the same, I wanted it to roll once more and sum all of the rolls. Until here, it was okay, but then I wanted to see not only sum, but also the numbers that computer generated randomly before adding them up. Therefore, it had to be several return types.
But it prints 0 three times instead.
Can you help me with this? I want to learn what is wrong exactly with this code and if it can be done neater and cleaner? I know Java loves long ways..
Thank you.
class App {
public static int monopolyRoll(int side) {
double randomNumber = Math.random();
randomNumber = randomNumber * side;
randomNumber = randomNumber + 1;
int randomInt = (int) randomNumber;
return randomInt;
}
private int roll1 = monopolyRoll(6);
private int roll2 = monopolyRoll(6);
public int userRolls() {
if (roll1 != roll2) {
return roll1 + roll2;
} else {
int roll3 = monopolyRoll(6);
int roll4 = monopolyRoll(6);
return roll1 + roll2 + roll3 + roll4;
}
}
private static int first;
private static int second;
private static int third;
public App(int first, int second, int third) {
App.first = roll1;
App.second = roll2;
App.third = userRolls();
}
public static int getFirst() {
return first;
}
public static int getSecond() {
return second;
}
public static int getThird() {
return third;
}
public static void main(String[] args) {
int first = getFirst();
int second = getSecond();
int third = getThird();
System.out.println(first);
System.out.println(second);
System.out.println(third);
}
}
Math.random() works, but you never actually call it in your application. This is what your application does:
int first = getFirst();
int second = getSecond();
int third = getThird();
System.out.println(first);
System.out.println(second);
System.out.println(third);
That's it. Aside from the single return statements in those getter methods and the declared-but-never-assigned integers they return (so, zeroes), none of that other code ever executes.
I suspect this is coming from a bit of a misunderstanding on your part about the static keyword. By sprinkling around the static keyword until the code compiled, what you've done is create something that's syntactically correct but doesn't do anything :)
As a bit of a learning exercise, try moving all of the business logic out of the App class, leaving only the main() method as the application's entry point. And removing all static keywords from the new class you create. This should make the use of that class more clear.
Something like:
class Roller {
private int roll1;
private int roll2;
// other private variables
private int monopolyRoll(int side) {
// your code
}
// your other methods, also private and non-static
public Roller(int first, int second, int third) {
this.first = roll1;
this.second = roll2;
this.third = userRolls();
}
// and so on
}
The idea here is to make things instance-based (non-static) by default. Also make things private by default until explicitly needed to be accessed outside the class. Currently the only things your class needs to expose publicly are the constructor and the getters.
Then in the main() method you'll need to create an instance of your class to use it. Something like this:
Roller roller = new Roller(1, 2, 3);
int first = roller.getFirst();
int second = roller.getSecond();
int third = roller.getThird();
System.out.println(first);
System.out.println(second);
System.out.println(third);

AspectJ - Is is possible to extend an enum's value?

Say I have an enum
public enum E {A,B,C}
Is it possible to add another value, say D, by AspectJ?
After googling around, it seems that there used to be a way to hack the private static field $VALUES, then call the constructor(String, int) by reflection, but seems not working with 1.7 anymore.
Here are several links:
http://www.javaspecialists.eu/archive/Issue161.html (provided by #WimDeblauwe )
and this: http://www.jroller.com/VelkaVrana/entry/modify_enum_with_reflection
Actually, I recommend you to refactor the source code, maybe adding a collection of valid region IDs to each enumeration value. This should be straightforward enough for subsequent merging if you use Git and not some old-school SCM tool like SVN.
Maybe it would even make sense to use a dynamic data structure altogether instead of an enum if it is clear that in the future the list of commands is dynamic. But that should go into the upstream code base. I am sure the devs will accept a good patch or pull request if prepared cleanly.
Remember: Trying to avoid refactoring is usually a bad smell, a symptom of an illness, not a solution. I prefer solutions to symptomatic workarounds. Clean code rules and software craftsmanship attitude demand that.
Having said the above, now here is what you can do. It should work under JDK 7/8 and I found it on Jérôme Kehrli's blog (please be sure to add the bugfix mentioned in one of the comments below the article).
Enum extender utility:
package de.scrum_master.util;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;
public class DynamicEnumExtender {
private static ReflectionFactory reflectionFactory =
ReflectionFactory.getReflectionFactory();
private static void setFailsafeFieldValue(Field field, Object target, Object value)
throws NoSuchFieldException, IllegalAccessException
{
// let's make the field accessible
field.setAccessible(true);
// next we change the modifier in the Field instance to
// not be final anymore, thus tricking reflection into
// letting us modify the static final field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
// blank out the final bit in the modifiers int
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers);
FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
fa.set(target, value);
}
private static void blankField(Class<?> enumClass, String fieldName)
throws NoSuchFieldException, IllegalAccessException
{
for (Field field : Class.class.getDeclaredFields()) {
if (field.getName().contains(fieldName)) {
AccessibleObject.setAccessible(new Field[] { field }, true);
setFailsafeFieldValue(field, enumClass, null);
break;
}
}
}
private static void cleanEnumCache(Class<?> enumClass)
throws NoSuchFieldException, IllegalAccessException
{
blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
blankField(enumClass, "enumConstants"); // IBM JDK
}
private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes)
throws NoSuchMethodException
{
Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
parameterTypes[0] = String.class;
parameterTypes[1] = int.class;
System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
return reflectionFactory.newConstructorAccessor(enumClass .getDeclaredConstructor(parameterTypes));
}
private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues)
throws Exception
{
Object[] parms = new Object[additionalValues.length + 2];
parms[0] = value;
parms[1] = Integer.valueOf(ordinal);
System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
}
/**
* Add an enum instance to the enum class given as argument
*
* #param <T> the type of the enum (implicit)
* #param enumType the class of the enum to be modified
* #param enumName the name of the new enum instance to be added to the class
*/
#SuppressWarnings("unchecked")
public static <T extends Enum<?>> void addEnum(Class<T> enumType, String enumName) {
// 0. Sanity checks
if (!Enum.class.isAssignableFrom(enumType))
throw new RuntimeException("class " + enumType + " is not an instance of Enum");
// 1. Lookup "$VALUES" holder in enum class and get previous enum
// instances
Field valuesField = null;
Field[] fields = enumType.getDeclaredFields();
for (Field field : fields) {
if (field.getName().contains("$VALUES")) {
valuesField = field;
break;
}
}
AccessibleObject.setAccessible(new Field[] { valuesField }, true);
try {
// 2. Copy it
T[] previousValues = (T[]) valuesField.get(enumType);
List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
// 3. build new enum
T newValue = (T) makeEnum(
enumType, // The target enum class
enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED
values.size(), new Class<?>[] {}, // could be used to pass values to the enum constuctor if needed
new Object[] {} // could be used to pass values to the enum constuctor if needed
);
// 4. add new value
values.add(newValue);
// 5. Set new values field
setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));
// 6. Clean enum cache
cleanEnumCache(enumType);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
}
}
Sample application & enum:
package de.scrum_master.app;
/** In honour of "The Secret of Monkey Island"... ;-) */
public enum Command {
OPEN, CLOSE, PUSH, PULL, WALK_TO, PICK_UP, TALK_TO, GIVE, USE, LOOK_AT, TURN_ON, TURN_OFF
}
package de.scrum_master.app;
public class Server {
public void executeCommand(Command command) {
System.out.println("Executing command " + command);
}
}
package de.scrum_master.app;
public class Client {
private Server server;
public Client(Server server) {
this.server = server;
}
public void issueCommand(String command) {
server.executeCommand(
Command.valueOf(
command.toUpperCase().replace(' ', '_')
)
);
}
public static void main(String[] args) {
Client client = new Client(new Server());
client.issueCommand("use");
client.issueCommand("walk to");
client.issueCommand("undress");
client.issueCommand("sleep");
}
}
Console output with original enum:
Executing command USE
Executing command WALK_TO
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant de.scrum_master.app.Command.UNDRESS
at java.lang.Enum.valueOf(Enum.java:236)
at de.scrum_master.app.Command.valueOf(Command.java:1)
at de.scrum_master.app.Client.issueCommand(Client.java:12)
at de.scrum_master.app.Client.main(Client.java:22)
Now you can either add an aspect with an advice executed after the enum class was loaded or just call this manually in your application before extended enum values are to be used for the first time. Here I am showing how it can be done in an aspect.
Enum extender aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Command;
import de.scrum_master.util.DynamicEnumExtender;
public aspect CommandExtender {
after() : staticinitialization(Command) {
System.out.println(thisJoinPoint);
DynamicEnumExtender.addEnum(Command.class, "UNDRESS");
DynamicEnumExtender.addEnum(Command.class, "SLEEP");
DynamicEnumExtender.addEnum(Command.class, "WAKE_UP");
DynamicEnumExtender.addEnum(Command.class, "DRESS");
}
}
Console output with extended enum:
staticinitialization(de.scrum_master.app.Command.<clinit>)
Executing command USE
Executing command WALK_TO
Executing command UNDRESS
Executing command SLEEP
Et voilà! ;-)

Alphabet Encryption

Right now I cant even compile this program. Im trying to write a program that takes a inputted string and then encrypts the letters by swapping them out with another letter predetermined in a array and then shows you again the original text. any help would be appreciated.
import java.util.Scanner;
public class Array {
private char [] alphabet = new char [25];
private char [] crypt = new char [25];
String oldMessage;
public Array()
{ char[] alphabet = "abcdefghijklmnoptqrstuvwxyz".toCharArray();
char[] crypt = "qwertyuiopasdfghjklzxcvbnm|".toCharArray();
}
public static void run(){
Scanner scan = new Scanner(System.in);
System.out.println("Enter a message that you would like to encrypt\n");
oldMessage = scan.nextLine();
String newMessage = "";
for (int i=0; i<oldMessage.length(); ++i) {
int index = alphabet.indexOf(old.charAt(i));
if (index == -1)
newMessage +="?";
else
newMessage += crypt.charAt(index);
/**
* #param args the command line arguments
*/
public static void main(String[] args) {Array myApplication = new Array(); myApplication.run();}
First off, when encountering errors, it's always best to include the error in your question--often it will point you right to the source of the error. What does your compiler say when the build fails?
Next, I'm on my phone right now and can't verify that I've found all the problems, but remember that strings in Java are immutable, meaning that they can't be changed after creation. This means that you can't append to them in the way you're doing. Try using the StringBuilder class to accomplish what you're looking for here, or filling a new array as you go and converting to String at the end.
Also, it looks like you're missing two end braces (the for loop and the run method).
From static method run() you are referring to non-static variables like alphabet, crypt, oldMessage.
This is first that comes into mind

Implement "Navigation bar" for custom editor

When registering a custom language service extension, Visual Studio creates a new options entry for the language within the Text Editor node (in the Visual Studio options dialog). Beneath that node two default nodes are created named General and Tabs, whereby the General tab contains statement completion and display settings...
In the Dispay group there are three options; one of them is the Navigation Bar checkbox (which shows/hides the editor´s navigation bar). For my custom language service, this option is disabled. Of course, it´s not implemented yet.
I would like to know, what I have to do, to provide a navigation bar for my custom editor... I guess that there is a certain interface I have to implement in the editor´s factory, or the language service package must export a certain MEF component, or, or, ...
Jon Senchyna´s answer guided me into the right direction. The OnSynchronizeDropdowns method gets never called (the SDK documentation is just wrong in that case). What did the final trick was to override at least GetComboAttributes, GetEntryAttributes and GetEntryText to get text-only items for both combo boxes...
[ComVisible(true)]
public sealed class CustomTypeAndMemberDropdownBars : TypeAndMemberDropdownBars
{
private readonly IList<string> declarations;
private readonly IList<string> members;
public CustomTypeAndMemberDropdownBars(
LanguageService languageService,
IVsTextView view)
: base(languageService)
{
// TODO: initialize declarations and members from the given text view...
this.declarations = ...
this.members = ...
}
private enum ComboIndex
{
Types = 0,
Members = 1
}
public override int GetComboAttributes(
int combo,
out uint entries,
out uint entryType,
out IntPtr imageList)
{
entries = 0;
imageList = IntPtr.Zero;
entryType = (uint)DROPDOWNENTRYTYPE.ENTRY_TEXT;
var comboType = (ComboIndex)combo;
switch (comboType)
{
case ComboIndex.Types:
entries = (uint)this.declarations.Count();
break;
case ComboIndex.Members:
entries = (uint)this.members.Count();
break;
}
return VSConstants.S_OK;
}
public override int GetEntryAttributes(
int combo,
int entry,
out uint fontAttrs)
{
fontAttrs = (uint)DROPDOWNFONTATTR.FONTATTR_PLAIN;
return VSConstants.S_OK;
}
public override int GetEntryText(
int combo,
int entry,
out string text)
{
text = null;
var comboType = (ComboIndex)combo;
switch (comboType)
{
case ComboIndex.Types:
text = this.declarations[entry];
break;
case ComboIndex.Members:
text = this.members[entry];
break;
}
return VSConstants.S_OK;
}
public override bool OnSynchronizeDropdowns(
LanguageService languageService,
IVsTextView textView,
int line,
int col,
ArrayList dropDownTypes,
ArrayList dropDownMembers,
ref int selectedType,
ref int selectedMember)
{
return false;
}
}
I believe the following steps should be what you need:
In your Package class, set the ShowDropDownOptions property to true in the ProvideLanguageService attribute
Create a class that implements TypeAndMemberDropdownBars
In your LanguageService class, implement the CreateDropDownHelper function and have it return an instance of your TypeAndMemberDropdownBars

Resources