Deep copying an array of objects - java

I'm still pretty new to Java and right now I'm trying to make a copy of Menu. I think I've done a little bit of it where I created a new Menu object with new MenuItems in it. MenuItems is another class with two string variables and a double variable, the itemName and itemDescription and the itemPrice. So I'm trying to copy the contents, the three variables of the original MenuItems into the MenuItems copy, but I don't know how. I got stuck on trying to set the clone copy's name to the original's name.
public class Menu
{
Menu()
{
}
final int maxItems = 50;
MenuItem[] food = new MenuItem[maxItems + 1];
public Object clone()
{
Menu menuClone = new Menu();
MenuItem[] foodClone = new MenuItem[maxItems + 1];
for(int i = 1; i <= maxItems + 1; i++)
{
foodClone[i] = new MenuItem();
foodClone[i] = food[i].setItemName();
}
}
This is the MenuItem class:
public class MenuItem
{
private String name;
private String descrip;
private double price;
MenuItem()
{
}
public String getItemName()
{
return name;
}
public String getItemDescrip()
{
return descrip;
}
public double getPrice()
{
return price;
}
public void setItemName(String itemName)
{
name = itemName;
}
public void setItemDescrip(String itemDescrip)
{
descrip = itemDescrip;
}
public void setPrice(double itemPrice) throws IllegalArgumentException
{
if(itemPrice >= 0.0)
price = itemPrice;
else
throw new IllegalArgumentException("Enter only positive values");
}
public String toString(){
return "Name: " + name + ", Desc: " + descrip;
}
}

You are almost there, where you have:
foodClone[i] = food[i].setItemName();
You probably want (in addition to the other variables of MenuItem)
foodClone[i].setItemName(food[i].getItemName())`
However, it's best to use the clone method or a copy constructor (well, copy constructor arguably might be best).
I do prefer using a copy constructor, such an example would be:
MenuItem(MenuItem menuItemToClone)
{
this.name = menuItemToClone.name;
this.descrip = menuItemToClone.descrip;
this.price = menuItemToClone.price;
}
Then you would just do:
foodClone[i] = new MenuItem(food[i]);

Cloning only provides a shallow copy, despite some of the previous recommendations.
A common solution to the deep copy problem is to use Java Object Serialization (JOS). The idea is simple: Write the object to an array using JOS’s ObjectOutputStream and then use ObjectInputStream to reconstitute a copy of the object. The result will be a completely distinct object, with completely distinct referenced objects. JOS takes care of all of the details: superclass fields, following object graphs, and handling repeated references to the same object within the graph. Figure 3 shows a first draft of a utility class that uses JOS for making deep copies.
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
/**
* Utility for making deep copies (vs. clone()'s shallow copies) of
* objects. Objects are first serialized and then deserialized. Error
* checking is fairly minimal in this implementation. If an object is
* encountered that cannot be serialized (or that references an object
* that cannot be serialized) an error is printed to System.err and
* null is returned. Depending on your specific application, it might
* make more sense to have copy(...) re-throw the exception.
*
* A later version of this class includes some minor optimizations.
*/
public class UnoptimizedDeepCopy {
/**
* Returns a copy of the object, or null if the object cannot
* be serialized.
*/
public static Object copy(Object orig) {
Object obj = null;
try {
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(orig);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
obj = in.readObject();
}
catch(IOException e) {
e.printStackTrace();
}
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return obj;
}
}
Unfortunately, this approach has some problems:
It will only work when the object being copied, as well as all of the other objects references directly or indirectly by the object, are serializable. (In other words, they must implement java.io.Serializable.) Fortunately it is often sufficient to simply declare that a given class implements java.io.Serializable and let Java’s default serialization mechanisms do their thing.
Java Object Serialization is slow, and using it to make a deep copy requires both serializing and deserializing. There are ways to speed it up (e.g., by pre-computing serial version ids and defining custom readObject() and writeObject() methods), but this will usually be the primary bottleneck.
The byte array stream implementations included in the java.io package are designed to be general enough to perform reasonable well for data of different sizes and to be safe to use in a multi-threaded environment. These characteristics, however, slow down ByteArrayOutputStream and (to a lesser extent) ByteArrayInputStream.
Source: http://javatechniques.com/blog/faster-deep-copies-of-java-objects/

Related

Java record serialization and repeated calls to canonical constructor

In this post about serializable records it is stated that
Deserialization creates a new record object by invoking a record class’s canonical constructor, passing values deserialized from the stream as arguments to the canonical constructor. This is secure because it means the record class can validate the values before assigning them to fields, just like when an ordinary Java program creates a record object via new. “Impossible” objects are impossible.
This argues with a constructor that is used for validation only. However, when the constructor manipulates the arguments this results in rather strange behavior. Consider this very artificial simple example:
The following record manipulates a before saving it:
import java.io.Serializable;
public record TRecord (int a) implements Serializable {
public TRecord {
a = a-1;
}
}
And the following program just saves the serialized record the first time and loads it the subsequent times:
import java.io.*;
public class TestRecords {
public static void main(String args[]) {
TRecord a1 = null;
try {
FileInputStream fileIn = new FileInputStream("tmp");
ObjectInputStream in = new ObjectInputStream(fileIn);
a1 = (TRecord) in.readObject();
in.close();
fileIn.close();
} catch (IOException | ClassNotFoundException i) {
// ignore for now
}
if (a1 == null) {
try {
a1 = new TRecord(5);
FileOutputStream fileOut = new FileOutputStream("tmp");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(a1);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
} catch (IOException i) {
i.printStackTrace();
}
}
System.out.println(a1);
}
}
The output for the first run is TRecord[a=4], and TRecord[a=3] in subsequent runs, so the state that I get from deserialization differs from what I put in there. Using a comparable class like the following instead would have gotten me the same result TClass[a=4] every time.
import java.io.Serializable;
public class TClass implements Serializable {
private int a;
public TClass(final int a) {
this.a = a-1;
}
public int getA() {return a;}
public String toString() {
return "Class[" + a + "]";
}
}
So my question is: Is there any rule for records that forbids/discourages using the constructor for anything other than validations (I am thinking for example about hashing a password before storing the input)? Or is there another way to deserialize an object so that the initial state is restored?
If you look at the documentation for records it says the following:
For all record classes, the following invariant must hold: if a record
R's components are c1, c2, ... cn, then if a record instance is copied
as follows:
R copy = new R(r.c1(), r.c2(), ..., r.cn());
then it must be the case that r.equals(copy).
This is not the case for your record class however:
jshell> TRecord r1 = new TRecord(42);
r1 ==> TRecord[a=41]
jshell> TRecord copy = new TRecord(r1.a());
copy ==> TRecord[a=40]
jshell> r1.equals(copy)
$4 ==> false
In other words, your record type violates this invariant, and this is also the reason why you are seeing the inconsistent deserialization.

storing the value of static variables in java

I have used a static variable in a Class and I want that the value of this variable is kept unchanged after restart of the jvm.
The idea is to store this value.
Can someone help me ?
If you want a variable whose value can change during the execution of the code, to be restored to whatever it was when you stopped the JVM, the next time you start the JVM, then you need to persist the value to an external medium. This is typically done by storing the value in a file or database, and retrieving it the next time the program starts. A key question when solving this problem is how to represent the value outside the executing program. For simple types like numbers and strings, this is not much of an issue. For values that are objects of non-trivial classes, the problem becomes more interesting. This is known as object serialization.
With the disclaimer that there are many different ways to persist data, here is a minimal example using Java Serialization to make the point more concrete.
class MyClassData implements Serializable {
private String myString = "A string";
private int myNumber = 5;
// To make the point that the state of the object stored in the
// variable can change at run-time.
public void changeThings( String myString, int myNumber) {
this.myString = myString;
this.myNumber = myNumber;
}
}
public class MyClass {
private static MyClassData data = restore();
// Call before exiting the program
private static void store() {
try( ObjectOutputStream out =
new ObjectOutputStream(new FileOutputStream("data.dat"))) {
out.writeObject(data);
}
catch( IOException e ) {
// Deal with this
}
}
private static MyClassData restore() {
try( ObjectInputStream in =
new ObjectInputStream(new FileInputStream("data.dat"))) {
return (MyClassData) in.readObject();
}
catch( IOException | ClassNotFoundException e ) {
return new MyClassData();
}
}
}
You restart the jvm every thing will be clear.So you can't get the values from static variables. If you use database then only you get the values without failing.

How to return Struct from Hive UDF?

I am having trouble finding documentation on how to use a Hive UDF to return a Struct.
My major questions are:
What types of objects do I start with in Java?
How do I convert them so they will be interpreted as a Struct in Hive?
Here is a very simple example of such kind of UDF.
It receives an User-Agent string, parse it using external lib and returns a structure with 4 text fields:
STRUCT<type: string, os: string, family: string, device: string>
You need to extend GenericUDF class and override two most important methods: initialize and evaluate.
initialize() describes the structure itself and defines data types inside.
evaluate() fills up the structure with actual values.
You don't need any special classes to return, struct<> in Hive is just an array of objects in Java.
import java.util.ArrayList;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.Text;
import eu.bitwalker.useragentutils.UserAgent;
public class UAStructUDF extends GenericUDF {
private Object[] result;
#Override
public String getDisplayString(String[] arg0) {
return "My display string";
}
#Override
public ObjectInspector initialize(ObjectInspector[] arg0) throws UDFArgumentException {
// Define the field names for the struct<> and their types
ArrayList<String> structFieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> structFieldObjectInspectors = new ArrayList<ObjectInspector>();
// fill struct field names
// type
structFieldNames.add("type");
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
//family
structFieldNames.add("family");
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
// OS name
structFieldNames.add("os");
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
// device
structFieldNames.add("device");
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
StructObjectInspector si = ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames,
structFieldObjectInspectors);
return si;
}
#Override
public Object evaluate(DeferredObject[] args) throws HiveException {
if (args == null || args.length < 1) {
throw new HiveException("args is empty");
}
if (args[0].get() == null) {
throw new HiveException("args contains null instead of object");
}
Object argObj = args[0].get();
// get argument
String argument = null;
if (argObj instanceof Text){
argument = ((Text) argObj).toString();
} else if (argObj instanceof String){
argument = (String) argObj;
} else {
throw new HiveException("Argument is neither a Text nor String, it is a " + argObj.getClass().getCanonicalName());
}
// parse UA string and return struct, which is just an array of objects: Object[]
return parseUAString(argument);
}
private Object parseUAString(String argument) {
result = new Object[4];
UserAgent ua = new UserAgent(argument);
result[0] = new Text(ua.getBrowser().getBrowserType().getName());
result[1] = new Text(ua.getBrowser().getGroup().getName());
result[2] = new Text(ua.getOperatingSystem().getName());
result[3] = new Text(ua.getOperatingSystem().getDeviceType().getName());
return result;
}
}
There is a concept of SerDe ( serializer and deserialzer ) in HIVE that can be used with the kind of data format you are playing it. It serializes the objects (complex) and then de-serializes it according to the need.
For instance, if you have a JSON file, that contains objects and values, so you need a way to store that content in hive.
For that you weill use a JsonSerde, that is actually a jar file , containing the parser code written in java for playing around with Json data.
SO now you have a jar( SerDe), and the other requirement is for a schema to store that data.
For eg: for XML files you need XSD,
similarly for JSON you define object ,arrays and structures relations.
You can check this link:
http://thornydev.blogspot.in/2013/07/querying-json-records-via-hive.html
Please let me know if this helps and solves your purpose :)

Java reflection nested methods not modifying underlying object

I am taking in an array of methods and I want to chain them together to modify an object that I am working in.
For example I start with
"getStuff().get(1).get(3).setMoreStuff().put(stuff,6)"
I split it into an array called methods, and clean up the parameters inside each method and I try to modify this.
Object res = this;
String[] methods = targetString.split("\\.(?=\\D)");
for (String m : methods){
List<Object> params = new ArrayList<Object>();
List<Object> params = new ArrayList<Object>();
for (String p : m.split("\\(|,|\\)")) {
try {
if (p.indexOf(".") != -1){
double tempD = Double.parseDouble(p);
params.add(tempD);
} else {
int tempP = Integer.parseInt(p);
params.add(tempP);
}
} catch (Exception ex) { //not a number
params.add(p);
}
}
switch (params.size()) {
case 1:
res = res.getClass().getMethod(
params.get(0)
).invoke(res);
break;
case 2:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass()
).invoke(res, params.get(1));
break;
case 3:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass(),
params.get(2).getClass()
).invoke(res, params.get(1), params.get(2));
break;
}
in the end I notice that res has been modified the way that I expect. All the getters and setters are called correctly. But of course the underlying object "this" refers to has not been changed!
I guess I'm just calling the getters and setters of the copy I made in the first line!
now I can't just use
this.getClass().getMethod(...).invoke(...)
because I need to call the same getMethod on the object returned by this call.
To clarify:
Object res = this;
creates a "pointer" to this. So that when I call
res.getStuff().setStuff(foo)
this will also be modified.
but it seem that when I call
res = res.getStuff();
res = res.setStuff();
like I do in my loop,
this does not modify the underlying object this refers to?
Edit: Included more code as per request.
Edit2: added anther example, to clarify my problem.
Edit3: tried to add more code, its a bit hard to add a working program without including every class
Your general approach should be fine (although your approach to parameter conversion is somewhat ugly) - it's the specifics that are presumably causing you problems. Here's a short but complete program demonstrating calling methods and then seeing the difference afterwards:
import java.lang.reflect.*;
class Person {
private String name = "default";
public String getName() {
return name;
}
// Obviously this would normally take a parameter
public void setName() {
name = "name has been set";
}
}
class Test {
private Person person = new Person();
public Person getPerson() {
return person;
}
// Note that we're only declaring throws Exception for convenience
// here - diagnostic code only, *not* production code!
public void callMethods(String... methodNames) throws Exception {
Object res = this;
for (String methodName : methodNames) {
Method method = res.getClass().getMethod(methodName);
res = method.invoke(res);
}
}
public static void main(String[] args) throws Exception {
Test test = new Test();
test.callMethods("getPerson", "setName");
System.out.println(test.getPerson().getName());
}
}
The output is "name has been set" just as I'd expect. So see if you can simplify your code bit by bit, removing extra dependencies etc until you've got something similarly short but complete, but which doesn't work. I suspect you'll actually find the problem as you go.
Object does not change reference, its VALUE changes. So if you will call this.get("some key"), you will get value that the same value that you put using reflection.
Right?

Converting String to Pointer for JNA

I'm trying to use JNA to query the effective permissions for a file in Windows. Eventually, I plan on using the GetEffectiveRightsFromAcl function, but to do so, I need to provide a pointer to a populated TRUSTEE structure. The JNA Platform (platform.jar) doesn't appear define this struct, so I'm trying to define it myself instead. Here's what I have so far:
public static class TRUSTEE extends Structure {
public TRUSTEE() {
super();
}
public TRUSTEE(Pointer p) {
super(p);
read();
}
public Pointer pMultipleTrustee;
public int MultipleTrusteeOperation;
public int TrusteeForm;
public int TrusteeType;
public Pointer ptstrName;
}
I'm trying to populate the structure like this:
private TRUSTEE createTrusteeForCurrentUser() {
TRUSTEE result = new TRUSTEE();
result.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME;
result.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER;
String strName = "CURRENT_USER";
// How can I set result.ptstrName using strName?
}
This Google Groups thread recommends using String fields in structures when a char * is called for. However, I don't think this is appropriate in my situation, considering the ptstrName field is allowed to point to different types of things, depending on the value of TrusteeForm. So, I think I somehow need to convert from String to Pointer instead. I found the NativeString class in JNA, which would work, except it's a package-private class.
What's the recommended way to convert a Java String to a native format and obtain a Pointer to it? Am I even using the right data type for the TRUSTEE struct? I'm somewhat new to JNA, so please excuse me if I'm missing something obvious.
Update
I found a solution to my problem, but if anyone has a better solution I'd still like to hear it.
Assuming you want char * on the native side (you may need more memory allocated if the string contains non-ascii characters),
String myString = "CURRENT_USER";
Pointer m = new Memory(myString.length() + 1); // WARNING: assumes ascii-only string
m.setString(0, myString);
You can then use m wherever you need to reference the "native" string.
For wide strings (wchar_t *),
String myString = "CURRENT_USER";
Pointer m = new Memory(Native.WCHAR_SIZE * (myString.length() + 1));
m.setWideString(0, myString);
I solved the problem by copying the source code for package-private NativeString class and creating a public copy in my project. I had to make one minor alteration due to the use of a package-private method in the constructor.
Update: As #fragorl notes in the comments, the implementation of NativeString shown below is by now quite out-of-date.
Usage:
private static TRUSTEE createTrusteeForCurrentUser() {
TRUSTEE result = new TRUSTEE();
result.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME;
result.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER;
result.ptstrName = new NativeString("CURRENT_USER",true).getPointer();
result.write();
return result;
}
NativeString.java:
/** Provides a temporary allocation of an immutable C string
* (<code>const char*</code> or <code>const wchar_t*</code>) for use when
* converting a Java String into a native memory function argument.
*
* #author Todd Fast, todd.fast#sun.com
* #author twall#users.sf.net
*/
public class NativeString implements CharSequence, Comparable {
private Pointer pointer;
private boolean wide;
/** Create a native string (NUL-terminated array of <code>char</code>).<p>
* If the system property <code>jna.encoding</code> is set, its value will
* be used to encode the native string. If not set or if the encoding
* is unavailable, the default platform encoding will be used.
*/
public NativeString(String string) {
this(string, false);
}
/** Create a native string as a NUL-terminated array of <code>wchar_t</code>
* (if <code>wide</code> is true) or <code>char</code>.<p>
* If the system property <code>jna.encoding</code> is set, its value will
* be used to encode the native <code>char</code>string.
* If not set or if the encoding is unavailable, the default platform
* encoding will be used.
*
* #param string value to write to native memory
* #param wide whether to store the String as <code>wchar_t</code>
*/
public NativeString(String string, boolean wide) {
if (string == null) {
throw new NullPointerException("String must not be null");
}
// Allocate the memory to hold the string. Note, we have to
// make this 1 element longer in order to accommodate the terminating
// NUL (which is generated in Pointer.setString()).
this.wide = wide;
if (wide) {
int len = (string.length() + 1 ) * Native.WCHAR_SIZE;
pointer = new Memory(len);
pointer.setString(0, string, true);
}
else {
byte[] data = Native.toByteArray(string);
pointer = new Memory(data.length + 1);
pointer.write(0, data, 0, data.length);
pointer.setByte(data.length, (byte)0);
}
}
public int hashCode() {
return toString().hashCode();
}
public boolean equals(Object other) {
if (other instanceof CharSequence) {
return compareTo(other) == 0;
}
return false;
}
public String toString() {
String s = wide ? "const wchar_t*" : "const char*";
s += "(" + pointer.getString(0, wide) + ")";
return s;
}
public Pointer getPointer() {
return pointer;
}
public char charAt(int index) {
return toString().charAt(index);
}
public int length() {
return toString().length();
}
public CharSequence subSequence(int start, int end) {
return CharBuffer.wrap(toString()).subSequence(start, end);
}
public int compareTo(Object other) {
if (other == null)
return 1;
return toString().compareTo(other.toString());
}
}
try using Pointer class in http://jna.java.net/javadoc/com/sun/jna/Pointer.html.

Categories