I am beginning java, and started to play with serialization. I wonder if there is any way to write the deserialization function inside the class itself. Let me clarify what I mean: I can deserialize an object (i.e. from class Person) from within another class and it works:
public class Dummy{
...
public static void main(String args[])
{
...
Person father = null;
try {
FileInputStream load = new FileInputStream(saved_file);
ObjectInputStream in = new ObjectInputStream(load);
indiv = (Person) in.readObject();
in.close();
load.close();
} catch (...) { ... }
}
}
But, for being tidy, is it possible to move this inside the Person class as a function? For instance, to do something like this:
public class Person implements Serializable {
private boolean isOrphan = false;
private Person parent;
...
public void load(File saved_file) {
try {
FileInputStream load = new FileInputStream(saved_file);
ObjectInputStream in = new ObjectInputStream(load);
this = (Person) in.readObject(); // Error: cannot assign a value to final variabl this
in.close();
load.close();
} catch (...) { ... }
}
}
And then in the other class just call this:
public class Dummy{
...
public static void main(String args[])
{
...
Person father = null;
father.load(saved_file);
}
}
You can't call an instance method on an instance that doesn't exist yet. Even if your code could compile, you would get a NullPointerException because youĆ¹re calling a method on null.
Make your method static and make it return the deserialized instance. More generally, this is not a variable that you can assign, it's an immutable reference to an object.
public static Person load(File saved_file) {
try (FileInputStream load = new FileInputStream(saved_file);
ObjectInputStream in = new ObjectInputStream(load)) {
return (Person) in.readObject();
} catch (...) { ... }
}
public class Dummy {
public static void main(String args[]) {
Person father = Person.load(saved_file);
}
}
PS: I also added try-catch with resources instead of explicit close() because it's safer.
Related
//Singleton
public class MainList implements Serializable {
private static MainList instance = new MainList();
private MainList() {}
public static MainList getInstance() {
return instance;
}
}
//Trying to deserialize..
public MainWindow() {
//Importing the latest version if it exists in path
MainList mainListObj = MainList.getInstance();
try {
FileInputStream fis = new FileInputStream(path);
ObjectInputStream oin = new ObjectInputStream(fis);
mainListObj = (MainList) oin.readObject(); //HERE//////
}
catch (Exception exc) {
return;
}
}
Singleton-Object of class MainList is serialized & can be found by path.
On the line //HERE/// object successfully deserializing to mainListObj,
BUT it's local..
How can I make it global? I think it could be solved by chanching getInstance method..somehow..
Your case is not singleton.
In your case, you can simply provide a setter.
static void setInstance(MainList newInstance) {
instance = newInstance;
}
MainList.setInstance(mainListObj);
I have 2 java classes.
1) class1.java
public class class1
{
private class ParameterVariable
{
class2 c1;
String s;
ParameterVariable(String s)
{
this.s =s;
}
}
public void methodToTest(String s)
{
try
{
ParameterVariable pv = new ParameterVariable(s)
if(StringUtils.isNotEmpty(pv.c1.getPartNo()))
{
// Some Code
}
}
finally
{
// Some code
}
}
}
2) class2.java
public class class2
{
// pojo class
String partNo;
public String getPartNo()
{
return partNo;
}
public void setPartNo(String partNo)
{
this.partNo = partNo;
}
}
Now I want to create a Junit test case for my method. I am not able to get runtime value for class2 object.
Here is my work
private class1 = null;
protected Object createParamterVariableObject ( String s ) throws ClassNotFoundException, InstantiationException,
IllegalAccessException, InvocationTargetException,
NoSuchMethodException, SecurityException
{
Class clazz = Whitebox.getInnerClassType(class1.class, "ParameterVariable");
Constructor constructorForParameterVariable = clazz.getConstructor(String.java)
Object parameterVariableObject = constructorForParameterVariable.newInstance(String.java)
return parameterVariableObject;
}
#Test
public void junitTestCase() throws Exception
{
String s = "Sample";
Class clazz = null;
Object parameterVariableObject = null;
class2 cls2Object = new clsObject;
try
{
parameterVariableObject = createParamterVariableObject(s);
clazz = Whitebox.getInnerClassType(SupersedeImpl.class, "ParameterVariable");
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
class2 c2Object = new class2();
c2Object.setPartNo("NEW_PART_NO");
Field C1Field = (Field) parameterVariableObject.getClass().getDeclaredField("c1");
C1Field.set(parameterVariableObject, C1Field);
PowerMockito.whenNew(clazz).withArguments(s).thenReturn(parameterVariableObject);
class1 = PowerMockito.spy(class1);
class1.methodToTest(s);
// some assertion
}
I want to set some mocking value of part no that is object of class2.
Because my method is based on it.
I am getting null using these code. Can you please help me?
You can try by mocking the object class2 c1,
in your code there must be setter method that is injecting the object.
You can use that in you JUnit test case to return the mock object.
i.e. via doReturn().. when()..
After that you will get the mocked object in your code.
you can use when().. then() for other stuff.
My suggestion: make your life easier:
Change that inner class to a normal class
Create a factory that returns instances of that class
And then use dependency injection to give such a factory to your class under test. And use any ordinary mocking framework to create those objects.
Done. And not only do you avoid all those issues that complicate mocking in your version; you also end up with code that is less tightly coupled.
I've learnt how to unit test basic things within Android, e.g. getting and setting of methods as below etc. but when it comes to the more complex stuff like my actual code below, I'm a little flummoxed at what to do.
public class SurveyTest extends TestCase {
private Survey survey;
protected void setUp() throws Exception {
super.setUp();
survey = new Survey();
}
public void testGetId() {
long expected = (long) Math.random();
survey.setId(expected);
long actual = survey.getId();
Assert.assertEquals(expected, actual);
}
public void testGetTitle() {
String expected = "surveytitle";
survey.setTitle(expected);
String actual = survey.getTitle();
Assert.assertEquals(expected, actual);
}
My small code that I'm stuck on how to Junit Test in the format as above:
public abstract class PrimaryModel extends Observable implements Serializable{
protected void notifyModelChange()
{
setChanged();
notifyObservers();
}
public String serialize() throws IOException
{
ObjectOutputStream objOutStream = null;
ByteArrayOutputStream bytArrOutStream = null;
try
{
bytArrOutStream = new ByteArrayOutputStream();
objOutStream = new ObjectOutputStream(bytArrOutStream);
objOutStream.writeObject(this);
}
finally
{
String main = new String(bytArrOutStream.toByteArray());
objOutStream.close();
bytArrOutStream.close();
return main;
}
}
public static PrimaryModel deserialize(String data) throws IOException, ClassNotFoundException
{
ObjectInputStream objInputStream = new ObjectInputStream(new ByteArrayInputStream(data.getBytes()));
PrimaryModel obj = (PrimaryModel) objInputStream.readObject();
objInputStream.close();
return obj;
}
}
Something like a serialize/deserialize pair of methods is generally easily tested. You need to know that a round trip returns an object which is equivalent to the original.
private static class PrimaryModelSubclass extends PrimaryModel {
/* add methods as needed */
}
final PrimaryModel original = new PrimaryModelSubclass(7, "some string", 43.7);
final PrimaryModel wellTravelled = PrimaryModel.deserialize(original.serialize());
assertEquals(original, wellTravelled);
You will need hashCode and equals methods to be correctly defined as well.
Updated in response to comment
I'm not sure if I'm asking this right, as I'm attempting to teach myself Java. I have a class which contains my main method, and within this class are several subclasses that need access to my user settings using java.util.Properties. I have to create the properties object in every subclass in order to make it work, and I can't reference the object using configFilePath, it must be null. I'm wondering if I can create this public object within the parent class, so I don't need to create it in all of its subclasses? Here is my code, I'm really not sure I'm doing this right although it works.
public class Frame1 extends JFrame {
Settings config = new Settings(); //this is the object I want to reference within subclasses
class Update extends SwingWorker<Integer, Void> { //first subclass
#Override
protected Integer doInBackground() throws Exception {
Settings config = new Settings(configFilePath); //yet I have to create the object within every subclass, this time an argument is required.
String templateDir = config.getProperty("templatedir");
String writePath = config.getProperty("outputdir");
//do some logic code, not required for my question
}
#Override
protected void done() {
Update2 update2 = new Update2();
update2.execute(); //start the next subclass which also needs access to Settings(configFilePath)
}
}
}
public class Settings extends JFrame {
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
public Settings(String configFilePath) throws IOException {
this.configFilePath = configFilePath;
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
I'm not sure if I'm doing this right or not, it seems to work but seems to be rather redundant having to create the config object every time I need to access my user settings. I hope this hasn't been asked before, and if it has please link me, as I could not find it.
You can create the Setting class as a Singleton pattern, here is one example:
public class Settings extends JFrame{
String configFilePath = "C:/path/to/settings.properties";
Properties properties = new Properties();
private static Settings instance;
public static Settings getInstance(){
if(instance==null){
instance = new Setting();
}
return instance;
}
private Settings() throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(configFilePath);
properties.load(fis);
} catch (FileNotFoundException e) {
setDefaults();
} finally {
if (fis != null) {
fis.close();
}
}
}
}
Usage in any other class of your system:
Settings.getInstance().getProperty("...");
From Update you can use Frame1.this to access the this of Frame1 (because Update is an inner class of Frame1).
Then to access config you can use Frame1.this.config.
Here is a working example:
public class PrefixerFactory {
private String prefix; // Used by Prefixer
public PrefixerFactory(String prefix) {
this.prefix = prefix;
}
public Prefixer createPrefixer() {
return new Prefixer();
}
public class Prefixer { // Inner class
public String addPrefix(String value) {
// Using "prefix" from PrefixerFactory
return PrefixerFactory.this.prefix + value;
}
}
public static void main(String[] args) {
Prefixer helloPrefixer = new PrefixerFactory("Hello ").createPrefixer();
Prefixer goodbyePrefixer = new PrefixerFactory("Good bye ").createPrefixer();
System.out.println(helloPrefixer.addPrefix("world")); // Hello world
System.out.println(goodbyePrefixer.addPrefix("world")); // Good bye world
}
}
I have this class in Java (it's from JaCoCo Project):
public class MemoryMultiReportOutput implements IMultiReportOutput {
private final Map<String, ByteArrayOutputStream> files = new HashMap<String, ByteArrayOutputStream>();
private final Set<String> open = new HashSet<String>();
private boolean closed = false;
public OutputStream createFile(final String path) throws IOException {
assertFalse("Duplicate output " + path, files.containsKey(path));
open.add(path);
final ByteArrayOutputStream out = new ByteArrayOutputStream() {
#Override
public void close() throws IOException {
open.remove(path);
super.close();
}
};
files.put(path, out);
return out;
}
public void close() throws IOException {
closed = true;
}
public void assertEmpty() {
assertEquals(Collections.emptySet(), files.keySet());
}
public void assertFile(String path) {
assertNotNull(String.format("Missing file %s. Actual files are %s.",
path, files.keySet()), files.get(path));
}
public void assertSingleFile(String path) {
assertEquals(Collections.singleton(path), files.keySet());
}
public byte[] getFile(String path) {
assertFile(path);
return files.get(path).toByteArray();
}
public InputStream getFileAsStream(String path) {
return new ByteArrayInputStream(getFile(path));
}
public void assertAllClosed() {
assertEquals(Collections.emptySet(), open);
assertTrue(closed);
}
}
When I compile this class the Eclipse create MemoryMultiReportOutput.class and MemoryMultiReportOutput$1.class.
First question: Why Eclipse create the MemoryMultiReportOutput$1.class? Eclipse considers the ByteArrayOutputStream out a InnerClass?
But my problem is, when I load the MemoryMultiReportOutput.class how can I load the all innerclasses present in parent class?
To answer your first question:
final ByteArrayOutputStream out = new ByteArrayOutputStream() {
#Override
public void close() throws IOException {
open.remove(path);
super.close();
}
};
Here you are creating a subclass of the ByteArrayOutputStream on the fly, i.e anonymous. This is why you have another .class file.
To answer your second question:
You can only load parent inner classes, visible to the subclass, through the Superclass's instance object :
Superclass s = new Superclass();
Superclass.Subclass sub = s.new Subclass();
If the inner class is static i.e a top-level nested class (since there is no such thing as inner static class) can be instantiated like this:
Superclass.Subclass s = new Superclass.Subclass();
and it does not require an object instance of the superclass.
Hope this helps!
Your creating an anonymous inner class with the
new ByteArrayOutputStream()
That's why you see the MemoryMultiReportOutput$1.class file.
You don't need to do anything to load the inner classes. That will happen automatically.
If your asking how to access the inner class from another class that's a bit different. You would need to mark it public or provide an accessor that would return an instance of the class. Is that what you were asking?