How can I save this kind of map to file? (it should work for an android device too)
I tried:
Properties properties = new Properties();
for (Map.Entry<String, Object[]> entry : map.entrySet()) {
properties.put(entry.getKey(), entry.getValue());
}
try {
properties.store(new FileOutputStream(context.getFilesDir() + MainActivity.FileName), null);
} catch (IOException e) {
e.printStackTrace();
}
And I get:
class java.util.ArrayList cannot be cast to class java.lang.String (java.util.ArrayList and java.lang.String are in module java.base of loader 'bootstrap')
What should I do?
I was writing an answer based on String values serialization when I realized for your error that perhaps some value can be an ArrayList... I honestly don't fully understand the reasoning behind the error (of course, it is a cast, but I don't understand the java.util.ArrayList part)...
In any case, the problem is happening when you try storing your properties and it tries to convert your Object[] to String for saving.
In my original answer I suggested you to manually join your values when generating your file. It is straightforward with the join method of the String class:
Properties properties = new Properties();
for (String key : map.keySet()) {
Object[] values = map.get(key);
// Perform null checking
String value = String.join(",", values);
properties.put(key, value);
}
try {
properties.store(new FileOutputStream(context.getFilesDir() + MainActivity.FileName), null);
} catch (IOException e) {
e.printStackTrace();
}
For reading your values, you can use split:
Properties properties = new Properties();
Map<String, String> map = new HashMap<>();
InputStream in = null;
try {
in = new FileInputStream(context.getFilesDir() + MainActivity.FileName);
properties.load(in);
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(k);
// Perform null checking
String[] values = value.split(",");
map.put(key, value);
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I think you have a much better approach: please, just use the Java builtin serialization mechanisms to save and restore your information.
For saving your map use ObjectOutputStream:
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(context.getFilesDir() + MainActivity.FileName))){
oos.writeObject(map);
}
You can read your map back as follows:
Map<String, Object> map;
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(context.getFilesDir() + MainActivity.FileName))){
map = (Map)ois.readObject();
}
If all the objects stored in your map are Serializables this second approach is far more flexible and it is not limited to String values like the first one.
Related
I have a Hashmap as a source of data and I'm generating a separate pdf for each key. But when the hashmap length is greater than 2 I'm getting only the 2nd pdf. 2nd one overrides the 1st pdf.(I'm storing HTML in the body key as you can see in the code). I don't want to create separate HTML files and store them in sever.Is there any way where I can store the HTML and generate separate pdf for all keys in hashmap
public byte[] BulkPdf(Map jsonObject) throws ApplicationException, IOException {
LinkedHashMap<String, List<Map<String, Object>>> hashMapDept = new LinkedHashMap<>();
byte[] reportByte = null;
if (!hashMapDept.isEmpty()) {
Integer count = 0;
for (Entry<String, List<Map<String, Object>>> entry : hashMapDept.
entrySet()) {
String body = "";
Writer out = new StringWriter();
Configuration cfg = new Configuration();
try {
cfg.setObjectWrapper(new DefaultObjectWrapper());
String templateStr = UUID.randomUUID().
toString().
replaceAll("-",
"");
logger.debug("templatename --> ",
templateStr);
freemarker.template.Template freemarkerTemplate = new freemarker.template.Template(
templateStr,
new StringReader(html),
cfg);
freemarkerTemplate.process(jsonObject,
out);
body = out.toString();
} catch (TemplateException | IOException | ApplicationException e) {
logger.debug("template pdf exception --> ",
e.getMessage());
out.flush();
e.printStackTrace();
cfg.clearTemplateCache();
} finally {
out.flush();
cfg.clearTemplateCache();
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.withHtmlContent(body,
"pathforpdf");
builder.useFastMode();
builder.toStream(outputStream);
builder.run();
reportByte = outputStream.toByteArray();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return reportByte;
}
Is it possible to change the object type of an array list i.e. from an Object ArrayList to a specific object ArrayList. I have tried using a for each. Alternatively is there a way to change the filehandling method such that it can return a specific type depending on which file it reads from without duplicating code?
My Attempt:
ArrayList<Object> librarianList = FileHandling.getLibrarianRecords(fileName);
ArrayList<Librarian> libList = new ArrayList<>();
for (Object addType: librarianList) {
libList.add(addType);
}
getLibrarianRecords code
public static ArrayList<Object> getLibrarianRecords(String filename){
ArrayList<Object> fromFile = new ArrayList<>(); //Array of
// existing librarians
try{
FileInputStream fIS =
new FileInputStream(SYSTEM_PATH + filename);
ObjectInputStream oIS = new ObjectInputStream(fIS);
fromFile = (ArrayList<Object>)oIS.readObject();
} catch (IOException ex){
System.out.println("Failed to read from file " + ex.getMessage());
ex.printStackTrace(); //Catches an IO exception.
} catch (ClassNotFoundException ex){
System.out.println("Error class not found" + ex.getMessage());
ex.printStackTrace(); //Catches a class not found
// exception.
}
return fromFile; //Returns the array list.
}
It is rarely a good idea to read objects from a file like this. That said all you really need to do is to cast the result of oIS.readObject() to an ArrayList<Librarian> instead of carrying it to ArrayList<Object> (as you do now) and then amend the return type of getLibrarianRecords. Oh, and naturally also the type of the local variable fromFile.
public static ArrayList<Librarian> getLibrarianRecords(String filename){
ArrayList<Librarian> fromFile = new ArrayList<>(); //Array of
// existing librarians
try{
FileInputStream fIS =
new FileInputStream(SYSTEM_PATH + filename);
ObjectInputStream oIS = new ObjectInputStream(fIS);
fromFile = (ArrayList<Librarian>)oIS.readObject();
} catch (IOException ex){
System.out.println("Failed to read from file " + ex.getMessage());
ex.printStackTrace(); //Catches an IO exception.
} catch (ClassNotFoundException ex){
System.out.println("Error class not found" + ex.getMessage());
ex.printStackTrace(); //Catches a class not found
// exception.
}
return fromFile; //Returns the array list.
}
There should then be no need to loop over the list to actually do the type conversion on an element by element basis.
Thanks to #user3170251 for suggesting casting
ArrayList<Object> librarianList = FileHandling.getLibrarianRecords(fileName);
ArrayList<Librarian> libList = new ArrayList<>();
for (Object addType: librarianList) {
libList.add((Librarian) addType);
}
For changing the type this does work.
You can use this generic class definition
class ArrayListConverter<T> {
List<T> cast;
public ArrayListConverter(List<T> typeList){
cast = new ArrayList<>();
for (Object addType: typeList) {
cast.add((T)addType);
}
}
public List<T> getList(){
return cast;
}
}
Just do this:
ArrayListConverter<Librarian> conv = new ArrayListConverter<>(libList);
ArrayList<Librarian> libListOg = conv.getList();
I am not entirely sure why my method is not working. I am using a write a file method which basically uses a HashMap to write to an external text file. which is the below
public void writeAMap(HashMap<String, String> map, String filename)
{
if(map != null) {
try (FileWriter writer = new FileWriter(filename, true)) {
for(String key : map.keySet()) {
String value = map.get(key);
if(value == null) {
System.out.println("Warning: Null response for " +
key + " in writeAMap. Using a default.");
value = "I don't know what you mean?";
}
writer.write(key.trim());
writer.write('\n');
writer.write(value.trim());
writer.write('\n');
}
writer.close();
}
catch(IOException e) {
System.out.println("Problem writing file: " + filename +
" in writeAMap");
}
}
else {
System.out.println("Null map passed to writeAMap.");
}
}
I am then calling the above method, using the method below in a another class
public void mapWrite(HashMap<String, String>map)
{
help.writeAMap(map, "responses.txt");
}
Then I wrote the below method in order to call the above method in the main class,
if (input.contains("write")) {
HashMap<String, String> key = new HashMap<String, String>();
instruct.mapWrite(key);
}
This compiles fine and gives no errors, but it isn't actually writing to the external txt file. any help on figuring out why that is would be great.
I have a response coming from a web service, data is in JSON form.
JSONObject event:-
{
"15:00":{"type":1,"status":null,"appointment_id":null},
"16:00":{"type":1,"status":null,"appointment_id":null},
"17:00":{"type":1,"status":null,"appointment_id":null},
"18:00":{"type":1,"status":"1","appointment_id":5}
}
I don't know the key values, they are random. So when i iterate the data using iterator by fetching keys and hasNext(). It returns the data but changes the order of coming data.
Iterator AppoinmentIter = event.keys();
while(AppoinmentIter.hasNext()){
String appointmentTime = (String)AppoinmentIter.next();
JSONObject appointmentDetails = event.getJSONObject(appointmentTime);
}
I want the data in exact order in which it is coming.
I checked this link, it suggests to use LinkedHashMap. But here they are inserting the value by keys. And i don't know the keys in my data. So how can i iterate the data in correct order. Please help..
That's not how JSON works. It assumes order doesn't matter unless you have an array. If you want order to matter, you're using the wrong format- you need yo use an array of times->values rather than just times->value.
For your particular application, you can get the set of keys, then sort them with a custom comparator that uses the value parsed as a time to order them. But the built in libraries won't do it for you, because you aren't using JSON as its designed.
Vikas, as far as i understood your problem i managed to retrieve json object in expected format, hope this will help you. Enjoy!!
String s = "{ \"15:00\":{\"type\":1,\"status\":null,\"appointment_id\":null},\"16:00\":{\"type\":1,\"status\":null,\"appointment_id\":null},\"17:00\":{\"type\":1,\"status\":null,\"appointment_id\":null},\"18:00\":{\"type\":1,\"status\":\"1\",\"appointment_id\":5}}";
try {
JSONObject jobj = new JSONObject(s);
Iterator iter = jobj.keys();
while(iter.hasNext()){
String appointmentTime = String.valueOf(iter.next());
aRRaY.add(appointmentTime);
}
Collections.sort(aRRaY);
for(String key : aRRaY){
JSONObject appointmentDetails = jobj.getJSONObject(key);
System.out.println(key +" ----- "+appointmentDetails);
}
}
catch (JSONException e) {
e.printStackTrace();
}
I don't know the implementation you have done, and what 3pp you involved. But anyway, try below codes, you would get what you want.
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class Test {
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
String json = "{"
+ "\"15:00\":{\"type\":1,\"status\":null,\"appointment_id\":null}, "
+ "\"16:00\":{\"type\":1,\"status\":null,\"appointment_id\":null},"
+ "\"17:00\":{\"type\":1,\"status\":null,\"appointment_id\":null},"
+ "\"18:00\":{\"type\":1,\"status\":\"1\",\"appointment_id\":5}"
+ "}";
LinkedHashMap<String, LinkedHashMap<String, Integer>> fromJSON = fromJSON(
json, LinkedHashMap.class);
for (Entry<String, LinkedHashMap<String, Integer>> entry : fromJSON
.entrySet()) {
System.out.print(entry.getKey());
System.out
.println(" || status = " + entry.getValue().get("status"));
}
}
public static <T> T fromJSON(String input, Class<T> clazz) {
try {
return mapper.readValue(input != null ? input : "null", clazz);
} catch (JsonParseException e) {
throw new RuntimeException(e);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
I am currently writing a Java application to retrieve BLOB type data from the database and I use a query to get all the data and put them in a List of Map<String, Object> where the columns are stored. When I need to use the data I iterate the list to get the information.
However I got an OutOfMemoryError when I tried to get the list of rows more than a couple times. Do I need to release the memory in the codes? My code is as follows:
ByteArrayInputStream binaryStream = null;
OutputStream out = null;
try {
List<Map<String, Object>> result =
jdbcOperations.query(
sql,
new Object[] {id},
new RowMapper(){
public Object mapRow(ResultSet rs, int i) throws SQLException {
DefaultLobHandler lobHandler = new DefaultLobHandler();
Map<String, Object> results = new HashMap<String, Object>();
String fileName = rs.getString(ORIGINAL_FILE_NAME);
if (!StringUtils.isBlank(fileName)) {
results.put(ORIGINAL_FILE_NAME, fileName);
}
byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "AttachedFile");
results.put(BLOB, blobBytes);
int entityID = rs.getInt(ENTITY_ID);
results.put(ENTITY_ID, entityID);
return results;
}
}
);
int count = 0;
for (Iterator<Map<String, Object>> iterator = result.iterator();
iterator.hasNext();)
{
count++;
Map<String, Object> row = iterator.next();
byte[] attachment = (byte[])row.get(BLOB);
final int entityID = (Integer)row.get(ENTITY_ID);
if( attachment != null) {
final String originalFilename = (String)row.get(ORIGINAL_FILE_NAME);
String stripFilename;
if (originalFilename.contains(":\\")) {
stripFilename = StringUtils.substringAfter(originalFilename, ":\\");
}
else {
stripFilename = originalFilename;
}
String filename = pathName + entityID + "\\"+ stripFilename;
boolean exist = (new File(filename)).exists();
iterator.remove(); // release the resource
if (!exist) {
binaryStream = new ByteArrayInputStream(attachment);
InputStream extractedStream = null;
try {
extractedStream = decompress(binaryStream);
final byte[] buf = IOUtils.toByteArray(extractedStream);
out = FileUtils.openOutputStream(new File(filename));
IOUtils.write(buf, out);
}
finally {
IOUtils.closeQuietly(extractedStream);
}
}
else {
continue;
}
}
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(binaryStream);
}
Consider reorganizing your code so that you don't keep all the blobs in memory at once. Instead of putting them all in a results map, output each one as you retrieve it.
The advice about expanding your memory settings is good also.
You there are also command-line parameters you can use for tuning memory, for example:
-Xms128m -Xmx1024m -XX:MaxPermSize=256m
Here's a good link on using JConsole to monitor a Java application:
http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
Your Java Virtual Machine probably isn't using all the memory it could. You can configure it to get more from the OS (see How can I increase the JVM memory?). That would be a quick and easy fix. If you still run out of memory, look at your algorithm -- do you really need all those BLOBs in memory at once?