Implementing duplication or cloning in groovy/java - java

I have a method to duplicate(clone) as below
static duplicateRecord(record)
{
def copyRecord = [:]
record.each{ fieldname, value ->
if (value)
{
copyRecord [(fieldname)] = value?.clone()
}
}
return copyRecord
}
Do we have any clone() method in Groovy/java to accomplish the same functionality ?

This should do it.
Copied from: https://stackoverflow.com/a/13155429/889945
// standard deep copy implementation
def deepcopy(orig) {
bos = new ByteArrayOutputStream()
oos = new ObjectOutputStream(bos)
oos.writeObject(orig); oos.flush()
bin = new ByteArrayInputStream(bos.toByteArray())
ois = new ObjectInputStream(bin)
return ois.readObject()
}

I think you would need to implement the Cloneable interface. This post shows how to clone an object in Groovy without implementing the Cloneable interface, though I have not tested it.

Related

Creating a deep copy of a multi-level list?

I have:
ArrayList<ArrayList<ArrayList<Task>>> optimalPaths = new ArrayList<ArrayList<ArrayList<Task>>>();
I would like to create a deep copy of optimalPaths. The copy itself should contain no references whatsoever to optimalPaths. Would the following code work?
ArrayList<ArrayList<ArrayList<Task>>> altPaths = new ArrayList<ArrayList<ArrayList<Task>>>();
for (ArrayList<ArrayList<Task>> e : optimalPaths){
altPaths.add((ArrayList<ArrayList<Task>>) e.clone()); // Create deep copy of optimalPaths
}
I'm not sure if there are still references within altPaths on some level.
You may do it by yourself
for (ArrayList<ArrayList<Task>> outer : optimalPaths) {
ArrayList<ArrayList<Task>> newOuter = new ArrayList<>();
for (ArrayList<Task> inner : outer) {
ArrayList<Task> newInner = new ArrayList<>();
for (Task task: inner) {
newInner.add((Task) task.clone());
}
newOuter.add(newInner);
}
altPaths.add(newOuter);
}
You can use copy by serialization and deserialization if Task class doesnt have any transient fields that you want to copy:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(optimalPaths);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bis);
ArrayList<ArrayList<ArrayList<Task>>> copied = (ArrayList<ArrayList<ArrayList<Task>>>) in.readObject();
or use external class to do that: SerializationUtils from Apache Commons

`Cannot find symbol` when trying to access a property of a child class but the variable is of type superclass

Java noob here, I have a variable of type OutputStream and later on in the function I have a condition where I either assign OutputStream to a new instance of FileOutputStream or ByteArrayOutputStream, however whenever I try to access any property that belongs to any of the subclasses. I get a Error cannot find symbol.
Is there a way to keep the variable of the same parent class and try to tell the runtime that whenever I need to access the property it would be of the child's class type?
Here is some pseudo code
public void work(Map params)
{
OutputStream output = null;
if(params.isAFile)
{
output = new FileOutputStream();
}
else
{
output = new ByteArrayOutputStream();
}
...do some work that makes use of the OutputStreams class
if(isFile)
{
return output
}
else
{
mybuffer = output.buf; //it fails here with Cannot find symbol since output is of type OutputStream when it should be treated as type ByteArrayOutputStream
return myBuffer;
}
}
You have to cast it like this:
(ByteArrayOutputStream output).buf
Java doesn't know that it can safely call the method in ByteArrayOutputStream since OutputStream doesn't have that method.

Antlr4 grammar requires me to use setInterpreter

When i set up a grammar with antlr4, and generated it i see the following line throughout the parser
_errHandler.sync(this);
Which in turn, does
getInterpreter()
and then calls methods on it. By default this returns null, and thus parsing throws NPEs.
I glomed together something that gets around this
myparser.setInterpreter(new ParserATNSimulator(myparser, myparser.getATN(), mylexer.getInterpreter().decisionToDFA,
new PredictionContextCache()));
But I'm certain that is wrong. The odd thing is I don't see any examples address this requirement, so I'm wondering what i have done wrong that this even needs to be done.
Interesting TestRig works fine, w/o the setInterpreter line, here's what i'm doing:
PelLexer pl = new PelLexer(CharStreams.fromString(s));
CommonTokenStream tokens = new CommonTokenStream(pl);
SecureRandom r = new SecureRandom();
String clsName = Parser.class.getPackage().getName() + ".eval.Eval" + Math.abs(r.nextLong());
PelParser pp = new PelParser(tokens, clsName);
pp.setBuildParseTree(false);
// pp.setInterpreter(new ParserATNSimulator(pp, pp.getATN(), pl.getInterpreter().decisionToDFA, new PredictionContextCache()));
pp.addErrorListener(new PELErrorListener());
pp.blockStatements();
byte[] clzData = pp.getClassBytes();
PELClassLoader pcl = AccessController.doPrivileged(new PrivilegedAction<PELClassLoader>() {
#Override
public PELClassLoader run() {
return new PELClassLoader(Thread.currentThread().getContextClassLoader());
}
});
pcl.addClass(clsName, clzData);
Class<Evaluable> c = (Class<Evaluable>) pcl.loadClass(clsName);
return c.newInstance();
Here's the answer.
When you add a constructor to your parser, you DON'T want to call
super(tokens);
You want to call
this(tokens);
As the default constructor created in your parser does
public PelParser(TokenStream input) {
super(input);
_interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}

Determining the Efferent coupling between objects (CBO Metric) using the parsed byte-code generated by BCEL

I have built a program, which takes in a provided ".class" file and parses it using the BCEL, I've learnt how to calculate the LCOM4 value now. Now I would like to know how to calculate the CBO(Coupling between object) value of the class file. I've scoured the whole web, trying to find a proper tutorial about it, but I've been unable so far (I've read the whole javadoc regarding the BCEL as well and there was a similar question on stackoverflow but it has been removed). So I would like some help with this issue, as in some detailed tutorials or code snippets that would help me understand on how to do it.
OK, here you must compute the CBO of the classes within a whole set of classes. The set can be the content of a directory, of a jar file, or all the classes in a classpath.
I would fill a Map<String,Set<String>> with the class name as the key, and the classes it refers to:
private void addClassReferees(File file, Map<String, Set<String>> refMap)
throws IOException {
try (InputStream in = new FileInputStream(file)) {
ClassParser parser = new ClassParser(in, file.getName());
JavaClass clazz = parser.parse();
String className = clazz.getClassName();
Set<String> referees = new HashSet<>();
ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
for (Method method: clazz.getMethods()) {
Code code = method.getCode();
InstructionList instrs = new InstructionList(code.getCode());
for (InstructionHandle ih: instrs) {
Instruction instr = ih.getInstruction();
if (instr instanceof FieldOrMethod) {
FieldOrMethod ref = (FieldInstruction)instr;
String cn = ref.getClassName(cp);
if (!cn.equals(className)) {
referees.add(cn);
}
}
}
}
refMap.put(className, referees);
}
}
When you've added all the classes in the map, you need to filter the referees of each class to limit them to the set of classes considered, and add the backward links:
Set<String> classes = new TreeSet<>(refMap.keySet());
for (String className: classes) {
Set<String> others = refMap.get(className);
others.retainAll(classes);
for (String other: others) {
refMap.get(other).add(className);
}
}

Loading a class with custom ClassLoader without using a String

I have created a custom ClassLoader and want to load a class. I am using this code at the moment to load the class from the Jar:
ByteArrayInputStream byteIS = new ByteArrayInputStream(data);
JarInputStream jarIS = new JarInputStream(byteIS);
JarEntry je;
je = jarIS.getNextJarEntry();
byte[] classbytes = new byte[(int) je.getSize()];
jarIS.read(classbytes, 0, classbytes.length);
jarIS.close();
CustomClassLoader classLoader = new CustomClassLoader();
classLoader.setClassContent(classbytes);
Class c = classLoader.findClass("Main");
Object object = c.newInstance();
Method[] methods = object.getClass().getMethods();
Object returnValue = methods[0].invoke(null, new Object[]{new String[]{}});
In this sample above you can clearly see I am trying to load class Main. Now imagine that my friend also creates a Jar, I cannot know on beforehand what the name of the class is. How can I avoid the usage of a String as argument?
You might want to have a look at the ServiceLoader API. You can define a common interface for service implementations (classes) that you don't know a priori.

Categories