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
}
}
Related
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.
//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'm trying to serialize this Configuration object, but for the life of me I can't get it. I've checked everywhere including StackOverflow. Any help would be greatly appreciated.
Serialization Code:
public void serialize(String outFile)
throws IOException {
Configuration config = new Configuration().getConfiguration();
System.out.println(config.email);
try
{
FileOutputStream outputFile =
new FileOutputStream("/home/jason/Desktop/config.ser");
ObjectOutputStream objectOutput = new ObjectOutputStream(outputFile);
objectOutput.writeObject(config);
objectOutput.close();
outputFile.close();
}catch(IOException i)
{
i.printStackTrace();
}
System.out.println(config);
}
public void deSerialize()
throws FileNotFoundException, IOException, ClassNotFoundException {
Configuration config = new Configuration().getConfiguration();
try
{
FileInputStream inputFile = new FileInputStream("/home/jason/Desktop/config.ser");
ObjectInputStream objectInput = new ObjectInputStream(inputFile);
config = (Configuration) objectInput.readObject();
config.setConfiguration(config);
objectInput.close();
inputFile.close();
}catch(Exception e)
{
e.printStackTrace();
}
System.out.println(config);
}
And then I call it with the following code:
DataStore data = new DataStore().getInstance();
try {
data.deSerialize();
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
DataStore is a simple singleton, and takes no input parameters. It doesn't have any real variables, but simply employs the serialization functions.
Finally, here is my Configuration code:
public class Configuration implements Serializable{
private static final long serialVersionUID = 1388190376766023647L;
public static String email = "";
private static String ip = "";
private static String password = "";
private static String importNumber;
private static Configuration configuration;
private static int singleton = 0;
public String value_of_da_message;
public Configuration()
{}
public Configuration getConfiguration()
{
if(singleton == 0){
configuration = new Configuration();
singleton++;
return configuration;
}
else
return configuration;
}
public void setConfiguration(Configuration config)
{
configuration = config;
}
Any clue on where I'm going wrong? Thanks for the help.
Have a look here: Java static serialization rules?
Change your fields to be instance fields, which would better fit the singleton approach anyways.
The fields might be serialized but deserialization normally ignores static fields.
Additionally, it looks like you're reading to the temporary object:
config.setConfiguration(config);
This uses the read object twice and doesn't set the data of the singleton unless you keep that a static field (i.e. configuration in the Configuration class is the reference to the singleton and needs to be static)
Update:
Another hint: the static variable singleton might cause problems and is unneeded anyway. Just check configuration == null instead of singleton == 0.
Hint:
I try to help you with serialization in general, but in your special case you might want to use Properties instead which have built-in serialization features (.properties- and xml-files supported) and which are meant for configuration.
I'm having an issue with my configuration management class, it is not getting reloaded.
Let me show you part of my code:
public class ConfigurationManager extends XMLConfiguration
{
private static final Logger log = LoggerFactory.getLogger(ConfigurationManager.class);
private static final long serialVersionUID = 1L;
public static final String CONFIG_FILE_PATH = "/config.xml";
private static volatile ConfigurationManager instance = null;
private static Object lock = new Object();
// Instance management methods
public static ConfigurationManager getInstance()
{
return getInstance(CONFIG_FILE_PATH);
}
public static ConfigurationManager getInstance(String cfg)
{
if(instance == null)
{
synchronized(lock)
{
if(instance == null)
{
try
{
instance = new ConfigurationManager(cfg);
instance.dumpConfigurationToLog();
}
catch(Exception e)
{
log.error("Error calling getInstance. Method params", e);
}
}
}
}
return instance;
}
private Object loadedCfg;
private int reloadInterval;
private void dumpConfigurationToLog()
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
this.save(bos);
bos.flush();
}
catch(Exception e)
{
log.error("Error calling dumpConfigurationToLog. Method params", e);
}
}
#Override
public void configurationChanged(ConfigurationEvent event)
{
log.info("Enter Method configurationChanged params: {}", event);
if(event.isBeforeUpdate() == false)
{
makeUpdates();
log.info("Configuration file: {} has changed and reloaded...", loadedCfg);
dumpConfigurationToLog();
}
log.info("Return Method configurationChanged");
}
private void updateReloadInterval()
{
int newReloadInterval = getInt("global.reloadInterval") * 1000;
if(reloadInterval != newReloadInterval)
{
reloadInterval = newReloadInterval;
if(getReloadInterval() > 0)
{
FileChangedReloadingStrategy reloadStrategy = new FileChangedReloadingStrategy();
reloadStrategy.setRefreshDelay(getReloadInterval());
this.setReloadingStrategy(reloadStrategy);
}
else
if(getReloadInterval() == 0)
{
this.setReloadingStrategy(new InvariantReloadingStrategy());
}
else
{
log.error("Invalid reload interval for ConfigurationManager: {}", getReloadInterval());
}
}
}
private ConfigurationManager(String cfgFile) throws Exception, ConfigurationException
{
super();
loadedCfg = cfgFile;
if(System.class.getResource(cfgFile) != null)
this.setURL(System.class.getResource(cfgFile));
else
this.setURL(getClass().getResource(cfgFile));
this.load();
makeUpdates();
this.addConfigurationListener(this);
this.setThrowExceptionOnMissing(true);
}
private void makeUpdates()
{
updateReloadInterval();
}
public int getReloadInterval()
{
return reloadInterval;
}
}
Now that code works perfectly fine, I can read the configuration file, and work with it with no major problems, the issue is that it never gets reloaded on configuration changes. I've tried setting breakpoints and so, but it never gets into configurationChanged method.
Does anybody see something wrong here?
Well, after testing and analyzing, I've got to this conclusion, in order to have configurationChanged called, I need to make an explicit call to get values from configuration.
And that is something I was not doing.
The thing got fixed when I did that.
You're calling makeUpdates() after setting your ConfigurationListener.
Additionally, calling load() is no guarantee that an Event will get fired.
Lastly, is there anything actually calling addProperty(), etc for this extended class?
Only a small side issue: resource bundles are cached, you can call clearCache, unfortunately not per bundle but per class loader.
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?