I've looked at many places on serialization but can't seem to find a solution to my problem. I'm making an Email client program and I want to store every email I send as an object in a file and then be able to retrieve it.
The problem I encounter is that every time I use ObjectOutputStream's writeObject() method, it truncates the file instead of appending it. Then I tried storing the emails in an ArrayList and storing the ArrayList in the file. Like, everytime I want to store I would readObject() the ArrayList then add the new email to it and then write the ArrayList again to the file. But this method started throwing many exceptions(i.e InvalidClassException).
Is there a way to serialize objects such that I will be able to append them to the file each time I want to write a new email or any other workaround for this?
Thanks in advance, below is the EmailMessage class:
public class EmailMessage implements Serializable{//implement serializables
private String recipient;
private String subject;
private String content;
private String date;
public void setRecipient(String recipient)
{
this.recipient=recipient;
}
public String getRecipient()
{
return this.recipient;
}
public void setSubject(String subject){
this.subject=subject;
}
public void setContent(String content){
this.content=content;
}
public String getSubject(){
return this.subject;
}
public String getContent(){
return this.content;
}
public void setDate(String date)
{
this.date=date;
}
public String getDate()
{
return this.date;
}
public String printDetails()
{
String details="Recipient: "+getRecipient()+
"\nSubject: "+getSubject()+
"\nEmail content: "+getContent()+
"\nDate Sent: "+getDate();
return details;
}
}
Related
I am new to collections and looking for help. I am trying to search a map using a key, and return the values of the key which is from another object. This is my code so far.
public class Employer {
Map<String, NewHire> employee = new HashMap<>();
}
public void addEmployee(String fullName, String age, String location, String JobTitle) {
NewHire newEmployee = new NewHire(age, location, JobTitle);
this.employee.put(fullName, newEmployee);
}
The code for the other object is -
public class NewHire {
private String age;
private String location;
private String jobTitle;
}
public NewHire(String aAge, String aLocation, String aJobTitle) {
this.age = aAge;
this.location = aLocation;
this.jobTitle = aJobTitle;
}
I then create like so -
Employer CompanyA = new Employer();
CompanyA.addEmployee("JohnSmith", "23", "London", "Service Desk");
I wanted to create a method that can search the map for a key specified by the user, in this case "JohnSmith", and if found, it then shows me the age, location and jobTitle of that person but I really am not sure how I would go about this.
The best way to go about it in my opinion is the way Titulum said, using Optional.
I would just leave another way, a bit not so nice, but you may understand it better.
You can Override the toString() method in the NewHire class and use it, or create getters for the properties:
#Override
public String toString(){
return String.format("Age: %s\nLocation: %s\nJobTitle: %s", age, location, jobTitle);
}
// getters
public String getJobTitle() {
return jobTitle;
}
public String getLocation() {
return location;
}
public String getAge() {
return age;
}
On your Employer class, if you want to use the not so much nicer way of doing it (although i recommend using Optional):
public NewHire getEmployeeByName(String fullName){
return employee.get(fullName);
}
Then to use it:
Employer employer = new Employer();
employer.addEmployee("JohnSmith", "23", "London", "Service Desk");
NewHire newHire = employer.getEmployeeByName("sJohnSmith");
if(newHire != null) {
System.out.println(newHire.toString());
// using getters
System.out.println(newHire.getAge());
System.out.println(newHire.getJobTitle());
System.out.println(newHire.getLocation());
}
You can simply write the method as follows:
public Optional<NewHire> findByFullName(String fullName) {
return Optional.ofNullable(employee.get(fullName));
}
This will return you an Optional, which is an Object in Java that contains either something or nothing. To see if the Optional contains anything you can do:
Optional<NewHire> possiblyFoundNewHire = findByFullName("SomeName");
possibleFoundNewHire.ifPresent(newHire -> {
System.out.println(newHire); // Or formatted as you would like.
});
String variable - "isInitial" in below example is not getting converted into JSON. Is it possible to generate JSON structure for isInitial variable without modifying the EmployeePOJO class?
PS: converting the getter method to getIsInitial works.
Please find below POJO class used for generating the JSON:
public class EmployeePOJO {
private String firstName;
private String lastName;
private String isInitial;
private boolean isFirstNameAvailable;
private boolean hasLastNameAvailable;
private String hasHouse;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String isInitial()
{
return this.isInitial;
}
public void setInitial(String pInitial)
{
this.isInitial = pInitial;
}
public String getHasHouse() {
return hasHouse;
}
public void setHasHouse(String hasHouse) {
this.hasHouse = hasHouse;
}
public boolean isFirstNameAvailable() {
return isFirstNameAvailable;
}
public void setFirstNameAvailable(boolean firstNameAvailable) {
isFirstNameAvailable = firstNameAvailable;
}
public boolean isHasLastNameAvailable() {
return hasLastNameAvailable;
}
public void setHasLastNameAvailable(boolean hasLastNameAvailable) {
this.hasLastNameAvailable = hasLastNameAvailable;
}
}
Please find below main logic for POJO conversion:
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
public class JacksonPojoToJson {
public static void main(String[] args) throws IOException {
// Create ObjectMapper
ObjectMapper mapper = new ObjectMapper();
EmployeePOJO employeePOJO = new EmployeePOJO();
employeePOJO.setFirstName("FIRST NAME");
employeePOJO.setFirstNameAvailable(true);
employeePOJO.setLastName("last name");
employeePOJO.setHasLastNameAvailable(true);
employeePOJO.setInitial("true");
// Convert object to JSON string
String json = mapper.writeValueAsString(employeePOJO);
System.out.println(json);
}
}
Bad naming conventions. If you are using IDE let the IDE generate the getters and setters for you.
The isInitial method can be used as getter for a Boolean variable. Not a String variable.
So you can fix your POJO class (https://en.wikipedia.org/wiki/Plain_old_Java_object)
or you can use the #JsonProperty annotation (https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonProperty.html)
Use Lombok maven dependency for generate automatic getter & setter.
You have to use the correct naming of getters and setters for your variable for example:
private String isInitial;
For the above variable getter setter should be:
public String getIsInitial()
{
return this.isInitial;
}
public void setIsInitial(String isInitial)
{
this.isInitial = isInitial;
}
Note: I don't know your use case but name like isXXXX used for getters of boolean variables.
I would recommend using Lombok's #Getter and #Setter annotations to auto-generate your getter and setter methods. Using these, you will not run into issues with naming conventions etc.
Please see the following URL for more information:
https://projectlombok.org/features/GetterSetter
#Loizos - Thanks a lot for the suggestion #JsonProperty, it worked fine. I was looking at a solution without modifying the class - EmployeePOJO (since it is legacy code which we dont want to touch).
I got this resolved by using Mixins, which does not require modification in EmployeePOJO file.
Sample code which worked for me:
public interface EmployeePOJOMixIn {
#JsonProperty("isInitial")
public abstract String isInitial();
}
Then adding this Mixin to mapper (this will vary based on whether you are using fasterxml or codehaus)
https://www.leveluplunch.com/java/tutorials/024-modifying-fields-external-domain-jackson-mixin/ and https://medium.com/#shankar.ganesh.1234/jackson-mixin-a-simple-guide-to-a-powerful-feature-d984341dc9e2 are good sites which I referred for the solution.
The reason for this is that the setters/getters for boolean variables do not follow the pattern setVariableName/getVariableName.
You could see in your own code that it is like this:
public String isInitial()
{
return this.isInitial;
}
public void setInitial(String isInitial)
{
this.isInitial = isInitial;
}
Quick fix would be to create the setters/getters for boolean variables manually.
This (setter/getter creation issue) usually happens in eclipse, but I think IntelliJ handles this right.
I have used One-to-Many Mapping in my project. I have stored a list of clicks for every user.
But when I retrieve the list by calling getClicks() methodm Hibernate returns list in different format.
Something like this.
"[com.zednx.tech.persistence.Click#29df9a77]"
So I tried Reading Every value from the list and assign to a new List.
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
clicks.add(temp);
}
But when i print the items of new List it stills prints the same way.
I need to build a JSON from the resulting String of this list.
So if the list is returned in format, it wont help me.
I couldn't find anything regarding this except How to pretty print Hibernate query results?
I tried Arrays.ToString(Object o). But it doesn't work.
GSON builder part-
Gson gson = new GsonBuilder()
.registerTypeAdapter(Click.class, new MyTypeAdapter<Click>())
.create();
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
temp.setCom_to_recieve(c.getCom_to_recieve());
temp.setStore_name(c.getStore_name());
temp.setT_date(c.getT_date());
temp.setT_status(c.getT_status());
temp.setT_ticket(c.getT_ticket());
temp.setUid(c.getUid());
System.out.println(c.toString());
clicks.add(temp);
}
String json = gson.toJson(clicks, Click.class);
Click.java
#Entity
#Table(name="click")
public class Click {
#Id
#Column(name="t_ticket")
private String t_ticket;
#Column(name="uid",nullable=false)
private long uid;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
#ManyToOne
#JoinColumn(name="uid",
insertable=false, updatable=false,
nullable=false)
private Earning earning;
#Column(name="store_name")
private String store_name;
#Column(name="t_status")
private String t_status;
#Column(name="aff_source")
private String aff_source;
#Column(name="com_to_recieve")
private float com_to_recieve;
#Column(name="t_date")
private Date t_date;
#Column(name="cb_to_award")
private float cb_to_award;
#Column(name="cb_type")
private String cb_type;
public String getT_ticket() {
return t_ticket;
}
public void setT_ticket(String t_ticket) {
this.t_ticket = t_ticket;
}
public Earning getEarning() {
return earning;
}
public void setEarning(Earning earning) {
this.earning = earning;
}
public String getStore_name() {
return store_name;
}
public void setStore_name(String store_name) {
this.store_name = store_name;
}
public String getT_status() {
return t_status;
}
public void setT_status(String t_status) {
this.t_status = t_status;
}
public String getAff_source() {
return aff_source;
}
public void setAff_source(String aff_source) {
this.aff_source = aff_source;
}
public float getCom_to_recieve() {
return com_to_recieve;
}
public void setCom_to_recieve(float com_to_recieve) {
this.com_to_recieve = com_to_recieve;
}
public Date getT_date() {
return t_date;
}
public void setT_date(Date t_date) {
this.t_date = t_date;
}
public float getCb_to_award() {
return cb_to_award;
}
public void setCb_to_award(float cb_to_award) {
this.cb_to_award = cb_to_award;
}
public String getCb_type() {
return cb_type;
}
public void setCb_type(String cb_type) {
this.cb_type = cb_type;
}
Any Help is appreciated.
You need to implement a toString method, as your current Click class likely doesn't have one, so it just prints as the name of the class and instance identifier.
Okay, I could solve my problem finally.
I made another POJO without any annotations and Mapped the List items to that POJO class.
I think the problem was with Annotation of mapping on another class which I had in original POJO.
Also getString() method only helps in changing format of identifier. So basically it has nothing to do with JSON building unless you format getString() in form of JSON.
Hope it helps. If anyone wants new temp POJO I made I can post it if requested.
Thanks.
I'm looking to pass the reference of the dataSnapshot and key of each specific object into a custom 'Message' object.
I've tried using the key 'String key' within the Message.class but it appears to come back null.
Here is how my Message object currently is:
public class Message {
private String key;
private String sender_id;
private String sender_username;
private String receiver_username;
private String receiver_id;
private String chat_id;
private String message;
private Firebase ref;
private double createdAt;
private boolean read;
public Message() {
// empty default constructor, necessary for Firebase to be able to deserialize messages
}
public String getKey() { return key; }
public String getSender_id() { return sender_id; }
public String getSender_username() { return sender_username; }
public String getReceiver_username() { return receiver_username; }
public String getReceiver_id() { return receiver_id; }
public String getChat_id() { return chat_id; }
public String getMessage() { return message; }
public Firebase getRef() { return ref; }
public double getCreatedAt() { return createdAt; }
public boolean getRead() { return read; }
}
Any ideas, how I properly pass the dataSnapshot.getKey() String to the custom object? I don't see an example on the Firebase docs, and to be clear I'm using the "legacy Firebase", before they updated.
When you get a Message instance from a DataSnapshot, you are likely doing:
Message message = snapshot.getValue(Message.class)
Since this is starting from getValue(), the message will not contain the key of the DataSnapshot.
What you can do is set the key yourself after reading the Message:
Message message = snapshot.getValue(Message.class);
message.setKey(snapshot.getKey());
You'll want to mark the getKey() as #JsonIgnore in that case, to ensure that Jackson tries to auto-populate or serialize it.
I ended up adding a static method to create the object from the DataSnapshot:
public static Message FromSnapshot(DataSnapshot snapshot)
{
Message msg = snapshot.getValue(Message.class);
msg.setKey(snapshot.getKey());
return msg;
}
I am serializing Diagram class to GAE Datastore using Objectify. I can update (serialize) all the fields as many times as I want, except Integer arrowTypeId, that is only updated once, and after that keeps always the same value. If I leave the app and run it again, I can update again that value, but only once.
To update arroyTypeId I am calling sendDatabaseUpdateDiagramArrows(). This is what happens:
I call sendDatabaseUpdateDiagramArrows() with value 1
I set that value to the DiagramProxy.setArrowTypeId().
As a test, I change the diagram title to DiagramProxy.getArrowTypeId()
I call save()
On the DAO save(), the wrong value of ArrowTypeId is received (keeps the old one), but surprisingly, the Title has the right ArrowTypeId stored from step 3)
Changes are serialized with this problem. No exceptions are displayed.
Note that I am able to update ArrowTypeId value the first time, from default value 1 to 2. Buth the next time keeps always value 2.
Edit: If I change arrowTypeId to a String, I have the same issue.
DatabaseUtils.java
public static DiagramProxy sendDatabaseUpdateDiagramArrows(DialectiveRequestFactory requestFactory, Integer value, DiagramProxy cellDiagramProxy)
{
DiagramRequest diagramRequest = requestFactory.diagramRequest();
DiagramProxy newDiagramProxy = diagramRequest.edit(cellDiagramProxy);
Date date = new Date();
newDiagramProxy.setArrowTypeId(value);
newDiagramProxy.setTitle(Integer.toString(newDiagramProxy.getArrowTypeId()));
diagramRequest.save(newDiagramProxy).fire();
return cellDiagramProxy;
}
Diagram.java
#Entity
public class Diagram extends DatastoreObject{
#Indexed private String diagramId;
private String title;
private Integer arrowTypeId;
public String get_id() {
return diagramId;
}
public void set_id(String diagramId) {
this.diagramId = diagramId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getArrowTypeId() {
return arrowTypeId;
}
public void setArrowTypeId(Integer arrowTypeId) {
this.arrowTypeId = arrowTypeId;
}
}
DiagramProxy.java
#ProxyFor(value = Diagram.class, locator = ObjectifyLocator.class)
public interface DiagramProxy extends EntityProxy{
void set_id(String id);
void setTitle(String title);
void setArrowTypeId(Integer arrowTypeId);
Integer getArrowTypeId();
String get_id();
String getTitle();
}
DiagramDao.java
public class DiagramDao extends ObjectifyDao<Diagram>{
public void save(Diagram diagram)
{
this.put(diagram);
} }
Let me guess :) as I don't have experience with GAE datastore.
I don't get the point, why you make
#Indexed private String diagramId;
but getter and setter with non-standard names:
public String get_id() {
return diagramId;
}
public void set_id(String diagramId) {
this.diagramId = diagramId;
}
I'd rather go for:
#Indexed private String diagramId;
public String getDiagramId() {
return diagramId;
}
public void setDiagramId(String diagramId) {
this.diagramId = diagramId;
}
One more thing is that DiagramRequest code has not been published, maybe that could help in seeing the problem.