I am writing a Minecraft plugin based on spigot coding.
But there I have the following issue, I am trying to edit a configuration file through the plugin, but when I attempt to store the information the data is not stored. As an example when I change name from Archive to Archive Stats and reload the server. Then the configuration name returns to Archive.
Archive:
Material:
==: org.bukkit.inventory.ItemStack
v: 2586
type: BOOKSHELF
ArchiveAtStart: false
Name: Archive
when I change the name to "Archive Stats"
Archive:
Material:
==: org.bukkit.inventory.ItemStack
v: 2586
type: BOOKSHELF
ArchiveAtStart: false
Name: Archive Stats
and reloaded the server, it still changes back to "Archive"
Archive:
Material:
==: org.bukkit.inventory.ItemStack
v: 2586
type: BOOKSHELF
ArchiveAtStart: false
Name: Archive
so here are the 2 codes to show:
The class
package com.Fender.Bedrock.files;
import com.Fender.Bedrock.Bedrock;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class CustomConfig
{
private static Bedrock plugin;
public static File file;
private static FileConfiguration customFile;
public static void setup(Bedrock plugin1)
{
plugin = plugin1;
file = new File(plugin.getDataFolder(), "config.yml");
if(!file.exists())
{
try {
file.createNewFile();
}catch (IOException e){
}
}
customFile = new YamlConfiguration();
save();
try{customFile.load(file);}
catch (IOException | InvalidConfigurationException e)
{
e.printStackTrace();
}
}
public static FileConfiguration get()
{
return customFile;
}
public static void save()
{
try
{
customFile.save(file);
}catch (IOException e)
{
System.out.print("Couldn't save file!");
}
}
public static void load()
{
try
{
try {
try {
customFile.load(file);
}catch (InvalidConfigurationException i){
System.out.print("Couldn't load file!");
}
}catch (FileNotFoundException f)
{
System.out.print("Couldn't load file!");
}
}catch (IOException e)
{
System.out.print("Couldn't load file!");
}
}
public static void reload()
{
customFile = YamlConfiguration.loadConfiguration(file);
}
public boolean exists()
{
if(file.exists()){
return true;
}else
{
return false;
}
}
}
The method for the main class
public void FileCreate()
{
CustomConfig.setup(this);
CustomConfig.reload();
{
CustomConfig.get().addDefault("Name1", "§dHis");
CustomConfig.get().addDefault("Place", 1);
CustomConfig.get().createSection("Archive");
CustomConfig.get().getConfigurationSection("Archive").addDefault("Material", itemStack);
CustomConfig.get().getConfigurationSection("Archive").addDefault("ArchiveAtStart", false);
CustomConfig.get().getConfigurationSection("Archive").addDefault("Name", "Archive");
CustomConfig.get().createSection("noob").addDefault("help", false);
}
CustomConfig.get().options().copyHeader(true);
CustomConfig.get().options().copyDefaults(true);
CustomConfig.save();
//saveResource("config.yml", false);
this.saveDefaultConfig();
}
Finally, this is my plugin main method :
#Override
public void onEnable() {
FileCreate();
this.getConfig().options().copyDefaults(true);
this.saveConfig();
}
This issue appear because you can overriding lines at startup. More exactly, when adding default lines.
This will just add a default value, but not overriding:
CustomConfig.get().addDefault("Name1", "§dHis");
It's this that change everything:
CustomConfig.get().createSection("Archive");
You should keep using addDefault(). For section just use addDefault("mysection.key", "myval"), and so, in your case:
CustomConfig.get().addDefault("Archive.Name", "Archive");
Related
I get a resource leak warning in return new ArrayList<>();. The file is not writing in the friends.txt which I am trying to save list in a text file. Please help.
import java.io.*;
import java.util.ArrayList;
public class ReadWrite {
public void writeFriends(ArrayList<Friend> friends) {
FileOutputStream friendFile;
ObjectOutputStream friendWriter;
try {
friendFile = new FileOutputStream(new File("C:\\Users\\aa\\Desktop\\src\\friends.txt"));
friendWriter = new ObjectOutputStream(friendFile);
if(friends.size() >0) {
friendWriter.writeInt(friends.size());
for (Friend friend : friends) {
friendWriter.writeObject(friend);
}
}
else {
System.out.println("No data to write");
}
friendWriter.close();
friendFile.close();
} catch (FileNotFoundException e) {
System.out.println("File Not Found. Retry after creating File 'Friends.txt'");
} catch (IOException e) {
System.out.println("Stream cannot be initialized.");
}
}
public ArrayList<Friend> readFriends() {
FileInputStream friendFile;
ObjectInputStream friendReader;
ArrayList<Friend> friends = new ArrayList<>();
try {
friendFile = new FileInputStream(new File("C:\\Users\\aa\\Desktop\\src\\friends.txt"));
friendReader = new ObjectInputStream(friendFile);
int size = friendReader.readInt();
if(size > 0){
for (int i = 0; i < friendReader.readInt(); i++) {
friends.add((Friend) friendReader.readObject());
}
}
else{
System.out.println("Empty File");
return new ArrayList<>();
}
friendReader.close();
friendFile.close();
} catch (FileNotFoundException e) {
System.out.println("File Not Found. Retry after creating File 'Friends.txt'");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println("Stream cannot be inititalized");
}
return friends;
}
}
I am trying to save a list of friends in the friends.txt file. I see no output in the friends.txt file. Is it something to do with my location or FileOutputStream ?
You have two problems in your code.
There is a bug in the for loop in method readFriends of class ReadWrite.
The file friends.txt may not be closed.
Here is the corrected code. Note that I could not find the code for class Friend in your question so I wrote a minimal class. Since you are using serialization, I assume that class Friend implements interface Serializable.
Notes after the code.
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
public class ReadWrite {
public void writeFriends(ArrayList<Friend> friends) {
try (OutputStream friendFile = Files.newOutputStream(Paths.get("C:", "Users", "aa", "Desktop", "src", "friends.dat"));
ObjectOutputStream friendWriter = new ObjectOutputStream(friendFile)) {
if (friends.size() > 0) {
friendWriter.writeInt(friends.size());
for (Friend friend : friends) {
friendWriter.writeObject(friend);
}
}
else {
System.out.println("No data to write");
}
}
catch (FileNotFoundException e) {
System.out.println("File Not Found. Retry after creating File 'friends.dat'");
e.printStackTrace();
}
catch (IOException e) {
System.out.println("Stream cannot be initialized.");
e.printStackTrace();
}
}
public ArrayList<Friend> readFriends() {
ArrayList<Friend> friends = new ArrayList<>();
try (InputStream friendFile = Files.newInputStream(Paths.get("C:", "Users", "aa", "Desktop", "src", "friends.dat"));
ObjectInputStream friendReader = new ObjectInputStream(friendFile)) {
int size = friendReader.readInt();
if (size > 0) {
for (int i = 0; i < size; i++) {
friends.add((Friend) friendReader.readObject());
}
}
else {
System.out.println("Empty File");
return new ArrayList<>();
}
}
catch (FileNotFoundException e) {
System.out.println("File Not Found. Retry after creating File 'friends.dat'");
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
System.out.println("Stream cannot be inititalized");
e.printStackTrace();
}
return friends;
}
public static void main(String[] args) {
ArrayList<Friend> friends = new ArrayList<>();
Friend friend = new Friend("Jane");
friends.add(friend);
ReadWrite rw = new ReadWrite();
rw.writeFriends(friends);
ArrayList<Friend> newFriends = rw.readFriends();
System.out.println(newFriends);
}
}
class Friend implements Serializable {
private String name;
public Friend(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
In the for loop condition in method readFriends you have the following:
friendReader.readInt()
This means that in every loop iteration, you are trying to read another int from the file friends.txt. This call fails since there is only one int in the file. Hence you need to use size which is the variable that contains the only int in file friends.txt which you read before the for loop.
Since you are using serialization, it is recommended to give the file name an extension of .dat rather than .txt since the file is not a text file.
I always write printStackTrace() in my catch blocks since that helps me to locate the cause of the exception. You actually should not get a FileNotFoundException since Java will create the file if it doesn't exist. If Java fails to create the file, then it is probably because the user has no permission to create a file, so displaying an error message saying to create the file before running your code probably won't help.
Your code may successfully open the file and write some data to it and crash before you have written all the data. In that case, your code does not close the file. If you are using at least Java 7, then you should use try-with-resources to ensure that the files are always closed.
Java 7 also introduced NIO.2 as a better API for interacting with the computer's file system from Java code. I suggest that you use it as I have shown in the code, above.
I have a third-party library that requires the populating of a java File object at runtime. I have extended this code, but I do not need the file-related part. However, for my purposes, I am forced to create and use the File object and read from it.
Is there a way I can have the binary equivalent of an already-read file available at runtime? Or is there a way to have a file as byte-code already available for a File object? Please assume with my situation that going to a file-system to retrieve and open a file is not an option.
Thanks for any insights!
You can create a temp file and delete after your program finishes.
import java.io.*;
import java.nio.file.*;
public class Program {
public static final File EMPTY_FILE = createTmpFile("empty.dat");
private static final File createTmpFile(final String filename) {
String tmpDir = System.getProperty("java.io.tmpdir");
Path filePath = Paths.get(tmpDir, filename);
return filePath.toFile();
}
public static void main(String[] args) {
try {
// Do stuff...
System.out.println(EMPTY_FILE.getCanonicalPath());
Thread.sleep(2000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
// Cleanup...
EMPTY_FILE.delete();
}
}
}
If you need a PHYSICAL file on they system, you can create it like so:
import java.io.*;
import java.nio.file.*;
public class Program {
public static final String TMP_DIR = System.getProperty("java.io.tmpdir");
public static final File EMPTY_FILE = createTmpFile("empty.dat");
private static final File createTmpFile(final String filename) {
Path filePath = null;
try {
byte[] data = { 0 }; // Write a single byte of data
filePath = Files.write(Paths.get(TMP_DIR, filename), data);
} catch (IOException e) {
e.printStackTrace();
}
return filePath.toFile();
}
public static void main(String[] args) {
try {
// Do stuff...
System.out.println(EMPTY_FILE.getCanonicalPath());
Thread.sleep(2000);
} catch (InterruptedException | IOException e) {
e.printStackTrace();
} finally {
// Cleanup...
EMPTY_FILE.delete();
}
}
}
I am not sure why file , BankAccount.ser is empty after successful run of below code. BankAccount.ser file is a class path resource. After successful run of SuccessfulSerializationTestDriver , BankAccount.ser is zero bytes on disk and has no contents.
public class SuccessfulSerializationTestDriver {
public static void main(String[] args) {
long accountNumber=12033456;
String bankName="SBI";
String branch="NOIDA";
SerializableBankAccount sBankAccount = new SerializableBankAccount();
sBankAccount.setAccountNumber(accountNumber);
sBankAccount.setBankName(bankName);
sBankAccount.setBranch(branch);
try(FileOutputStream fileOut =new FileOutputStream("BankAccount.ser")){
ObjectOutputStream out= new ObjectOutputStream(fileOut);
out.writeObject(sBankAccount);
out.flush();
out.close();
System.out.println("Bank Account is successfully serialized");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Serializable class is ,
public class SerializableBankAccount implements Serializable {
private static final long serialVersionUID = 1L;
private long accountNumber;
private String bankName;
private String branch;
public long getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(long accountNumber) {
this.accountNumber = accountNumber;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
#Override
public String toString(){
return accountNumber+","+bankName+","+branch;
}
}
EDIT : I wrote deserializer and I am getting object successfully - so it just seems a visibility issue. Somehow file is shown of zero bytes.
public class SuccessfulDeSerializationTestDriver {
public static void main(String[] args) {
SerializableBankAccount sBankAccount = null;
try(FileInputStream fileIn =new FileInputStream("BankAccount.ser")){
ObjectInputStream inStream= new ObjectInputStream(fileIn);
sBankAccount= (SerializableBankAccount) inStream.readObject();
inStream.close();
System.out.println("Successfully Deserialized Object is "+sBankAccount);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Successfully Deserialized Object is 12033456,SBI,NOIDA
If the file you're looking at is zero bytes, but it deserializes successfully, it sounds like the file is being created elsewhere. Perhaps specify the path explicitly when you create the file name for a start. The file with size 0, may be from an older run - delete that on disk, and see if it gets created again.
I am not able to recreate the problem you're having. When I run your code the BankAccount.ser file is created and is not empty. In fact I wrote a deserialization test to see if I could get the object back by reading the file and it works fine.
Here is the deserializing class in case you want it:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializationTestDriver {
public static void main(String[] args) {
try(FileInputStream fileInput =new FileInputStream("BankAccount.ser")){
ObjectInputStream input = new ObjectInputStream(fileInput);
SerializableBankAccount sBankAccount = (SerializableBankAccount) input.readObject();
input.close();
System.out.println("Bank Account is successfully deserialized: "+sBankAccount.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
I also added a toString method to your SerializableBankAccount:
#Override
public String toString() {
return "SerializableBankAccount [accountNumber=" + accountNumber
+ ", bankName=" + bankName + ", branch=" + branch + "]";
}
After running your serialization code and then running the above deserialization I get this output:
Bank Account is successfully deserialized: SerializableBankAccount [accountNumber=12033456, bankName=SBI, branch=NOIDA]
So clearly the code is fine, which means it has to be something to do with the environment. I suggest checking whether you're running the program with correct privileges, permissions, etc. It seems that something external to your code is preventing you from writing to the file. Either that or perhaps you're looking at the wrong file, verify you have the correct path and check the file creation and modification dates.
I use eclipse and put a File called "example.txt" into the bin-folder where the class files are generated (and into the sub-folder of the package). But still, the program allways prints out the error message i wrote for the case the file is not found.
Main Class:
import java.io.BufferedReader;
public class Main {
public static void main(String[] args){
BufferedReader file = Console.file("example.txt");
...
}
Console Class:
public final class Console {
public static BufferedReader file(String args) {
BufferedReader file = null;
try {
file = new BufferedReader(new FileReader(args));
} catch (FileNotFoundException e) {
println("Error, file not found!");
System.exit(1);
}
return file;
}
}
any ideas?
For the Eclipse project, the current path is the project folder, not the BIN directory, you can use the code below to get the current path so that you will know where to put and how to access the file.
import java.io.File;
import java.io.IOException;
public class MainTest {
public static void main(String[] args)
{
File directory = new File("");
try {
System.out.println(directory.getCanonicalPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
So in your case, the path you specify should be: ./bin/example.txt
So i've decided to try to write a thing that will loads a specific .class file from a .jar that anyone puts into a folder. (Right now it only loads my Test.jar)
The thing is, that these classes implements an interface in the java project that i'm loading them from, and i get an error telling me that the class "Klass" doesn't exist.
How can i get the loader to load that one instead of trying to use it's own?
(Also, this is what i think it's doing, i have no idea if it's true)
The code for loading the .jar:
String filePath = new String("C:/classes/Test.jar");
URL myJarFile = null;
try {
myJarFile = new URL("file:///"+filePath);
URL[] urls = new URL[]{myJarFile};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompan
Class cls = cl.loadClass("me.bluejelly.survivalgames.classes.Test");
try {
Klass klass = (Klass) cls.newInstance();
klass.create(arg0.getName());
Main.listeners.put(arg0.getName(), klass);
Bukkit.getPluginManager().registerEvents(klass, instance);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
And this it the code in the file i'm trying to load:
package me.bluejelly.survivalgames.classes;
import me.bluejelly.survivalgames.Main;
import me.bluejelly.survivalgames.def.Klass;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.ItemStack;
public class Test implements Klass {
private String ownerName;
#Override
public void create(String pName) {
this.ownerName = pName;
Main.listeners.put(this.ownerName, this);
}
#Override
public void destroy() {
if(Main.listeners.containsKey(this.ownerName)) {
Main.listeners.remove(ownerName);
}
HandlerList.unregisterAll(this);
}
#Override
public Material getIcon() {
return null;
}
#Override
public ItemStack[] getStartingItems() {
return null;
}
#EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if(event.getPlayer().getName().equals(ownerName)) {
Bukkit.broadcastMessage("test");
}
}
}
You need to set the main class loader as the parent of your new URLClassLoader. That way it will pick up your local Klass class.
Something like...
ClassLoader cl = new URLClassLoader(urls, getClass().getClassLoader());