I have this class that implements Cloneable. I only need a shallow copy here. Can anyone point to what is wrong with the java compliance here.
public class EventSystem implements Cloneable{
private String enrollmentId;
private String requestId;
private String tokenId;
private Date eventAt;
private Date loggedAt;
private String appCardId;
private String fieldKey;
private String fieldValue;
private String trsDimCardIssuerId;
private String trsDimCardProductId;
private String trsDimAppEventLocationId;
private String trsDimPaymentNetworkId;
private String trsDimAppCardTypeId;
private String trsTempLogId;
public Date getEventAt() {
return eventAt;
}
public void setEventAt(Date eventAt) {
this.eventAt = eventAt;
}
public Date getLoggedAt() {
return loggedAt;
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = loggedAt;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getEnrollmentId() {
return enrollmentId;
}
public void setEnrollmentId(String enrollemntId) {
this.enrollmentId = enrollemntId;
}
public String getTokenId() {
return tokenId;
}
public void setTokenId(String tokenId) {
this.tokenId = tokenId;
}
public String getTrsDimCardIssuerId() {
return trsDimCardIssuerId;
}
public void setTrsDimCardIssuerId(String trsDimCardIssuerId) {
this.trsDimCardIssuerId = trsDimCardIssuerId;
}
public String getTrsDimCardProductId() {
return trsDimCardProductId;
}
public void setTrsDimCardProductId(String trsDimCardProductId) {
this.trsDimCardProductId = trsDimCardProductId;
}
public String getTrsDimAppEventLocationId() {
return trsDimAppEventLocationId;
}
public void setTrsDimAppEventLocationId(String trsDimAppEventLocationId) {
this.trsDimAppEventLocationId = trsDimAppEventLocationId;
}
public String getTrsDimPaymentNetworkId() {
return trsDimPaymentNetworkId;
}
public void setTrsDimPaymentNetworkId(String trsDimPaymentNewtorkId) {
this.trsDimPaymentNetworkId = trsDimPaymentNewtorkId;
}
public String getTrsDimAppCardTypeId() {
return trsDimAppCardTypeId;
}
public void setTrsDimAppCardTypeId(String trsDimAppCardTypeId) {
this.trsDimAppCardTypeId = trsDimAppCardTypeId;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
#Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getTrsTempLogId() {
return trsTempLogId;
}
public void setTrsTempLogId(String trsTempLogId) {
this.trsTempLogId = trsTempLogId;
}
public String getAppCardId() {
return appCardId;
}
public void setAppCardId(String appCardId) {
this.appCardId = appCardId;
}
public String getFieldKey() {
return fieldKey;
}
public void setFieldKey(String fieldKey) {
this.fieldKey = fieldKey;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
}
Is there a problem with String copy here.
Your String fields aren't a problem. Your Date fields are.
When you clone an EventSystem instance, each of its fields points to exactly the same object as source object’s corresponding field. Thus, a cloned instance’s enrollmentId field points to the same String object as the original instance’s enrollmentId.
But that’s perfectly okay. You can safely share String objects, because they’re immutable. A String object cannot be altered. You can change value of a field which holds a String, but the String object itself can never change.
However, Date objects can be changed. This means the clone is not truly independent of the source instance. They both refer to the same mutable object, so if that object is changed for just one of the two EventSystem instances, both instances will see the changes, which can lead to some insidious bugs. Consider this code:
Calendar calendar = Calendar.getInstance();
calendar.set(1969, Calendar.JULY, 20, 22, 56, 0);
Date moonLanding = calendar.getTime();
EventSystem e1 = new EventSystem();
e1.setEventAt(moonLanding);
// Prints Sun Jul 20 22:56:00 EDT 1969
System.out.println(e1.getEventAt());
EventSystem e2 = (EventSystem) e1.clone();
// Both e1 and e2 have references to the same Date object, so changes
// to that Date object are seen in both objects!
e2.getEventAt().setTime(System.currentTimeMillis());
// You might expect these to be different, since we only changed
// e2.getEventAt(), but they're the same.
System.out.println(e1.getEventAt());
System.out.println(e2.getEventAt());
One way to resolve this is to use a common object-oriented technique known as defensive copying:
public Date getEventAt() {
return (eventAt != null ? (Date) eventAt.clone() : null);
}
public void setEventAt(Date eventAt) {
this.eventAt = (eventAt != null ? (Date) eventAt.clone() : null);
}
public Date getLoggedAt() {
return (loggedAt != null ? (Date) loggedAt.clone() : null)
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = (loggedAt != null ? (Date) loggedAt.clone() : null);
}
This prevents any other classes from directly modifying the internal Date field.
Another, less safe option is to clone the Date fields in your clone method:
#Override
public Object clone() throws CloneNotSupportedException {
EventSystem newInstance = (EventSystem) super.clone();
if (newInstance.eventAt != null) {
newInstance.eventAt = (Date) newInstance.eventAt.clone();
}
if (newInstance.loggedAt != null) {
newInstance.loggedAt = (Date) newInstance.loggedAt.clone();
}
return newInstance;
}
Related
I have an issue with realm. I receive a custom object from an API. I assign this object to a POJO object using retrofit. Within this object I have an ArrayList of the ToDoItemobject which extends RealmObject.
I receive the data correctly with all attributes, everything gets correctly assigned. I run it through my synchronization algorithm and save it to realm in a writing transaction. But when retrieving the data after realm.commit(); the attributes of the objects are all 0 or null.
The method isManaged()is always false, even after the writing transaction, which I don't understand because in the official documentation is states that a POJO can be converted to a managed object using the copyToRealm method.
I already tried a number of things: creating the GetItemResponseClass as RealmObject, but not possible since it has to extend JSONObject to correctly receive the data from the API. I also tried to write the whole list directly to realm but the result was the same.
As a side note, it can be that my method syncPendingLists has some logic errors, but I couldn't debug it yet, since the attributes were always o and null. Thanks for any help.
Here my code from the Activity:
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
RealmResults<Counter> counterList = realm.where(Counter.class).findAll();
//setting up counterObject
if (counterList.isEmpty()) {
counterObject = new Counter();
COUNTER = counterObject.getCounter();
} else {
counterObject = counterList.get(0);
COUNTER = counterObject.getCounter();
}
initializeLists();
//Adding the Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new DoneListFragment(), "DoneListFragment");
ft.add(R.id.fragment_container, new PendingListFragment(), "PendingListFragment");
ft.commit();
RetrofitClient retrofitClient = new RetrofitClient();
Retrofit retrofit = retrofitClient.getClient();
mAPIInterface = retrofit.create(ToDoistAPIInterface.class);
}
public void getRemoteItems() {
final ArrayList<ToDoItem> onlineItems = new ArrayList<ToDoItem>();
JSONArray array = new JSONArray();
array.put("items");
String auxMessage = array.toString();
mAPIInterface.getItems(RetrofitClient.TOKEN, "*", auxMessage).enqueue(new Callback<GetItemsResponseClass>() {
#Override
public void onResponse(Call<GetItemsResponseClass> call, Response<GetItemsResponseClass> response) {
GetItemsResponseClass itemsResponseClass = new GetItemsResponseClass();
itemsResponseClass = response.body();
remoteItemsList = itemsResponseClass.getItems();
boolean test = remoteItemsList.get(0).isManaged(); //returns false
boolean test1 = remoteItemsList.get(0).isValid(); //returns true refers to singleton RealmObject
syncPendingLists(pendingItemList, remoteItemsList);
}
#Override
public void onFailure(Call<GetItemsResponseClass> call, Throwable t) {
Snackbar.make(floatingButton, "Ups - Couldn't sync items, next time, I promise", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initializeLists() {
RealmResults<ToDoItem> realmToDoItemPendingList = realm.where(ToDoItem.class).equalTo("checkedOffline", false).findAll();
initializingArrayListFromDB(realmToDoItemPendingList, pendingItemList);
RealmResults<ToDoItem> realmToDoItemDoneList = realm.where(ToDoItem.class).equalTo("checkedOffline", true).findAll();
initializingArrayListFromDB(realmToDoItemDoneList, doneItemList);
}
private void initializingArrayListFromDB(RealmResults<ToDoItem> realmToDoItemPendingList, ArrayList<ToDoItem> arrayList) {
int h;
for (h = 0; h < realmToDoItemPendingList.size(); h++) {
arrayList.add(realmToDoItemPendingList.get(h));
}
}
public void syncPendingLists(ArrayList<ToDoItem> offlinePendingList, ArrayList<ToDoItem> onlinePendingList) {
//is my sync algorithm, the important part is the for loop at the end of this method
boolean hasMatch = false;
boolean itemChanged = false;
Date offlineDate = null;
Date onlineDate = null;
if (!offlinePendingList.isEmpty()) {
for (ToDoItem item1 : offlinePendingList) {
if (item1.getId() < 10000) {
try {
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
for (int i = 0; i < onlinePendingList.size(); i++) {
if (item1.getId() == onlinePendingList.get(i).getId()) {
hasMatch = true;
onlinePendingList.remove(onlinePendingList.get(i));
//Compare Fields
if (!item1.getContent().equals(onlinePendingList.get(i).getContent())) {
itemChanged = true;
}
if (item1.getPriority() != onlinePendingList.get(i).getPriority()) {
itemChanged = true;
}
if (!item1.getDate_string().equals(onlinePendingList.get(i).getDate_string())) {
itemChanged = true;
}
if (itemChanged == true) {
//Format edit dates to date
DateFormat format = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
try {
offlineDate = format.parse(item1.getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
try {
onlineDate = format.parse(onlinePendingList.get(i).getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
//compare dates to see which was last edited
if (offlineDate.compareTo(onlineDate) > 0) {
try {
deleteRemoteItem(onlinePendingList.get(i), "item_delete");
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (offlineDate.compareTo(onlineDate) < 0) {
addOrUpdateToDB(item1);
}
}
}
if (!hasMatch) {
deleteObjectFromDB(item1);
}
}
}
}
}
for (ToDoItem onlineItem1 : onlinePendingList) {
boolean isManaged1 = onlineItem1.isManaged(); //returns false, which is ok since it is not yet in the realm db
onlineItem1.setLocalId(counterObject.getCounter());
addOrUpdateToDB(onlineItem1);
boolean asdf = onlineItem1.isManaged(); //it returns false, but it should return true
incrementCounter(counterObject);
}
initializeLists();
getPendingListFragment().refreshFragment();
}
private void addOrUpdateToDB(ToDoItem newItem) {
boolean test2= newItem.isManaged(); //returns false
realm.beginTransaction();
realm.copyToRealmOrUpdate(newItem);
//realm.copyToRealm(newItem); //I tried this method as well, but no difference
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and here is the problem, it should return true, shouldn't it?
assignValuesToToDoItem(itemWithValues, newItem);
saveCounterToDB(counterObject);
}
}
Here my class code of ToDoItem:
public class ToDoItem extends RealmObject implements Parcelable {
public static final Creator<ToDoItem> CREATOR = new Creator<ToDoItem>() {
#Override
public ToDoItem createFromParcel(Parcel in) {
return new ToDoItem(in);
}
#Override
public ToDoItem[] newArray(int size) {
return new ToDoItem[size];
}
};
#PrimaryKey
private long localId;
private String content;
private boolean checkedOffline = false;
private int priority;
private String date_string;
private String temp_id;
private long id;
private String date_added;
public ToDoItem(String name) {
this.content = name;
}
public ToDoItem() {
}
protected ToDoItem(Parcel in) {
localId = in.readLong();
content = in.readString();
checkedOffline = in.readByte() != 0;
priority = in.readInt();
date_string = in.readString();
temp_id = in.readString();
id = in.readLong();
date_added=in.readString();
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isCheckedOffline() {
return checkedOffline;
}
public void setCheckedOffline(boolean checkedOffline) {
this.checkedOffline = checkedOffline;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setRemote_id(Long remote_id) {
this.id = remote_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isDone() {
return checkedOffline;
}
public String getDate_string() {
return date_string;
}
public void setDate_string(String date_string) {
this.date_string = date_string;
}
public long getLocalId() {
return this.localId;
}
public void setLocalId(long i) {
this.localId = i;
}
public String getTemp_id() {
return temp_id;
}
public void setTemp_id(String temp_id) {
this.temp_id = temp_id;
}
public String getDateAdded() {
return date_added;
}
public void setDateAdded(String dateAdded) {
this.date_added = dateAdded;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(localId);
dest.writeString(content);
dest.writeByte((byte) (checkedOffline ? 1 : 0));
dest.writeInt((priority));
dest.writeString(date_string);
dest.writeString(temp_id);
dest.writeLong(id);
dest.writeString(date_added);
}
#Override
public String toString() {
return "localId: " + localId + "; content: " + content;
}
}
And here the code for the GetItemsResponseClass:
public class GetItemsResponseClass extends JSONObject {
private String sync_token;
#SerializedName("temp_id_mapping")
private HashMap<String, Long> temp_id_mapping;
private boolean full_sync;
#SerializedName("items")
private ArrayList<ToDoItem> items;
public GetItemsResponseClass(){
}
public String getSync_token() {
return sync_token;
}
public void setSync_token(String sync_token) {
this.sync_token = sync_token;
}
public HashMap<String, Long> getTemp_id_mapping() {
return temp_id_mapping;
}
public void setTemp_id_mapping(HashMap<String, Long> temp_id_mapping) {
this.temp_id_mapping = temp_id_mapping;
}
public boolean isFull_sync() {
return full_sync;
}
public void setFull_sync(boolean full_sync) {
this.full_sync = full_sync;
}
public ArrayList<ToDoItem> getItems() {
return items;
}
public void setItems(ArrayList<ToDoItem> items) {
this.items = items;
}
}
EDIT: Apparently it is a desired behavior that the object does not get saved with its attributes. Consequently to assign the values you have to use getters and setters. I added the following method, however even when debugging with a watch, as stated in the official documentation the values do not get assigned:
private void assignValuesToToDoItem(ToDoItem itemWithValues, ToDoItem newItem) {
realm.beginTransaction();
newItem.setContent(itemWithValues.getContent()); //the content variable stays null
newItem.setCheckedOffline(itemWithValues.isDone()); //stays false
newItem.setPriority(itemWithValues.getPriority());
newItem.setDate_string(itemWithValues.getDate_string());
newItem.setTemp_id(itemWithValues.getTemp_id());
newItem.setId(itemWithValues.getId());
newItem.setDate_added(itemWithValues.getDate_added());
realm.commitTransaction();
}
I added this line assignValuesToToDoItem(itemWithValues, newItem); in the main activity in the method private void addOrUpdateToDB(ToDoItem newItem) {...}
Same result...
I found out 2 very important things:
The attributes are saved, however in the debugging window they appear to be 0, false or null
Even putting a Debugging Watch does not show the correct values.
To see the real value how it is in the database you have to add a Watch and put the watch directly on the getters of the object. In my case I added a Watch and typed in "newItem.getContent()". With this line I got the title of my object. However just putting a Watch with "newItem" shows "null".
copyToRealm() and copyToRealmOrUpdate() returns the managed proxy as a return value of the function you're calling.
realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and it should return false
Should be
newItem = realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns true
I've got a problem with my programm. When i try to compile following i just receive the message:
Tutorium.java:15: error: <identifier> expected
public void settName(vorlesung.lectureName) {
^
So my Code:
Tutorium.java
public class Tutorium {
private Vorlesung vorlesung;
public String tName;
private int tNumber;
public int gettNumber() {
return this.tNumber;
}
public String gettName() {
return this.tName;
}
public void settName(vorlesung.lectureName) {
this.tName = vorlesung.lectureName;
}
public String toString() {
return (this.tName + ", " + this.tNumber);
}
public Tutorium(int tNumber){
this.tNumber = tNumber; } }
Vorlesung.java
public class Vorlesung {
public String lectureName;
private int lectureNumber;
private int lecture;
private Dozent dozent;
private String lecturerlName;
public String getlectureName(){
return this.lectureName;
}
public int lectureNumber(){
return this.lectureNumber;
}
public int lecture(){
return this.lecture;
}
public String getlecturer(){
this.lecturerlName = dozent.lecturerlName;
return this.lecturerlName;
}
public String toString() {
return (this.lectureName + ", " + this.lectureNumber);
}
public Vorlesung(String lectureName, int lecture) {
this.lectureName = lectureName;
this.lecture = lecture +1;
this.lectureNumber = this.lecture -1;
this.lecturerlName = lecturerlName;
}}
My Main-Method:
public class MainVorlesung {
public static void main(String[] args) {
Student student = new Student("STUDENTNAME", "STUDENTLASTNAME", 178, 1);
Vorlesung vorlesung = new Vorlesung("Programmieren", 13341);
Tutorium tutorium = new Tutorium(3);
Dozent dozent = new Dozent("LECTURERFIRSTNAME", "LECTURERLASTNAME", 815);
System.out.println(student.toString());
System.out.println(vorlesung.toString());
System.out.println(tutorium.toString());
System.out.println(dozent.toString());
}}
My goal is to set the value of tName equal the value of vorlesung.lectureName.
Why can't i do this that way?
I appreciate every help. :)
Thanks
For methods, the arguments that you pass in must have a declared value.
In this case, a String. So you need to change your method to this:
public void settName(String newLectureName) {
this.tName = newLectureName;
}
Read more about what a java method is and how to create one here: http://www.tutorialspoint.com/java/java_methods.htm
Change settName to
public void settName(String name) {
this.tName = name;
}
Since your goal is:
My goal is to set the value of tName equal the value of vorlesung.lectureName.
You should get rid of the setName method entirely since it will depend entirely on the vorlesung field and so should not be changeable. You should also get rid of the tName field, and instead change getName() to:
public class Tutorium {
private Vorlesung vorlesung;
// public String tName; // get rid of
private int tNumber;
public String gettName() {
if (vorlesung != null) {
return vorlesung.getlecturer();
}
return null; // or throw exception
}
// *** get rid of this since you won't be setting names
// public void settName(Vorlesung vorlesung) {
// this.tName = vorlesung.lectureName;
// }
I have just now noticed that your Tutorium class does not have and absolutely needs a setVorlesung(...) method.
public void setVorlesung(Vorlesung vorlesung) {
this.vorlesung = vorlesung;
}
Output of below class is :
size is 3
size is 1
But if I change the TreeSet to a HashSet so line :
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
becomes
Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();
the output is :
size is 3
size is 2
Shout using HashSet or TreeSet not change the size of Set ?
Using HashSet seems to behave as expected because it is removing duplicates but when I use TreeSet the duplicates remain ?
I think the hashcode and equals methods in SuggestionDetailBean are overriden correctly ?
Here is the code :
public class TestSet {
public static void main(String args[]){
SuggestionDetailBean s = new SuggestionDetailBean();
s.setTagList("teddst");
s.setUrl("testurl");
SuggestionDetailBean s2 = new SuggestionDetailBean();
s2.setTagList("teddst");
s2.setUrl("testurl");
SuggestionDetailBean s3 = new SuggestionDetailBean();
s3.setTagList("tessdafat");
s3.setUrl("fdfaasdfredtestur ldd");
List<SuggestionDetailBean> list = new ArrayList<SuggestionDetailBean>();
list.add(s);
list.add(s2);
list.add(s3);
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
set.addAll(list);
System.out.println("size is "+list.size());
System.out.println("size is "+set.size());
}
}
public class SuggestionDetailBean implements Comparable<Object> {
private String url;
private String tagList;
private String numberOfRecommendations;
private String date;
private String time;
private String summary;
private String truncatedUrl;
public void setTruncatedUrl(String truncatedUrl) {
if(truncatedUrl.length() > 20){
truncatedUrl = truncatedUrl.substring(0, 20)+"...";
}
this.truncatedUrl = truncatedUrl;
}
public String getSummary() {
if(summary == null){
return "";
}
else {
return summary;
}
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTime() {
return time;
}
public String getTruncatedUrl() {
return this.truncatedUrl;
}
public void setTime(String time) {
this.time = time;
}
public String getTagList() {
if(tagList == null){
return "";
}
else {
return tagList;
}
}
public void setTagList(String tagList) {
this.tagList = tagList;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getNumberOfRecommendations() {
return numberOfRecommendations;
}
public void setNumberOfRecommendations(String numberOfRecommendations) {
this.numberOfRecommendations = numberOfRecommendations;
}
#Override
public int compareTo(Object o) {
DateFormat formatter;
Date date1 = null;
Date date2 = null;
SuggestionDetailBean other = (SuggestionDetailBean) o;
if(this.date == null || other.date == null){
return 0;
}
formatter = new SimpleDateFormat(SimpleDateFormatEnum.DATE.getSdfType()+" "+SimpleDateFormatEnum.TIME.getSdfType());
try {
date1 = (Date) formatter.parse(this.date + " " + this.time);
date2 = (Date) formatter.parse(other.date + " " + other.time);
} catch (ParseException e) {
System.out.println("Exception thrown in"+this.getClass().getName()+", compareTo method");
e.printStackTrace();
}
catch(NullPointerException npe){
System.out.println("Exception thrown "+npe.getMessage()+" date1 is "+date1+" date2 is "+date2);
}
return date2.compareTo(date1);
}
#Override
public int hashCode() {
return this.url.hashCode();
}
#Override
public boolean equals(Object obj) {
SuggestionDetailBean suggestionDetailBean = (SuggestionDetailBean) obj;
if(StringUtils.isEmpty(this.getTagList())){
return this.getUrl().equals(suggestionDetailBean.getUrl());
}
else {
return (this.getTagList().equals(suggestionDetailBean.getTagList())) &&
(this.getUrl().equals(suggestionDetailBean.getUrl()));
}
}
}
Edit :
Note : if I convert the hashset to a treeset using :
Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);
Then correct sorting is maintained, as the removal of duplicates is based on the object hashcode and equals methods not the compareto method.
According to the Javadoc for TreeSet:
Note that the ordering maintained by a set (whether or not an explicit
comparator is provided) must be consistent with equals if it is to
correctly implement the Set interface. (See Comparable
or Comparator for a precise definition of consistent with
equals.) This is so because the Set interface is defined in
terms of the equals operation, but a TreeSet instance
performs all element comparisons using its compareTo (or
compare) method, so two elements that are deemed equal by this method
are, from the standpoint of the set, equal. The behavior of a set
is well-defined even if its ordering is inconsistent with equals; it
just fails to obey the general contract of the Set interface.
So, the problem is with your compareTo method: either it's giving inconsistent results, or else it's giving consistent results that don't obey the rule that a.compareTo(b) == 0 if and only if a.equals(b).
For example, this bit:
if(this.date == null || other.date == null){
return 0;
}
means "if either this or other has date == null, then report that this and other are equal", which is certainly not what you want.
I have a method that return an object of a class.The object sets the properties of class and returns.
I have to traverse the object and get the value of the properties which the object has set before.
I tried to use for-each loop,iterator but failed to traverse.
Can someone please help me to get through this.Thanks in advance.
code:
public class ConsumerTool {
public MessageBean getMessages() {
MessageBean msgBean = new MessageBean();
msgBean.setAtmId(atmId.trim());
msgBean.setEventText(eventText.trim());
msgBean.setEventNumber(eventNumber.trim());
msgBean.setSeverity(severity.trim());
msgBean.setSubsystemID(subsystemID.trim());
msgBean.setUniqueEventID(uniqueEventID.trim());
msgBean.setTaskID(taskID.trim());
msgBean.setGenerator(generator.trim());
msgBean.setGeneratorBuildVsn(generatorBuildVsn.trim());
msgBean.setDateTime(dateTime.trim());
this.msgBean = msgBean;
return msgBean;
}
}
JavaBean class:
public class MessageBean implements java.io.Serializable {
public String dateTime;
public String severity;
public String eventText;
public String eventNumber;
public String generator;
public String generatorBuildVsn;
public String atmId;
public String uniqueEventID;
public String subsystemID;
public String taskID;
//System.out.println("dateTime2222222"+dateTime);
public String getAtmId() {
return this.atmId;
}
public void setAtmId(String n) {
this.atmId = n;
}
public String getDateTime() {
return this.dateTime;
}
public void setDateTime(String n) {
this.dateTime = n.trim();
}
public String getEventNumber() {
return this.eventNumber;
}
public void setEventNumber(String n) {
this.eventNumber = n;
}
public String getEventText() {
return this.eventText;
}
public void setEventText(String n) {
this.eventText = n;
}
public String getGenerator() {
return this.generator;
}
public void setGenerator(String n) {
this.generator = n;
}
public String getGeneratorBuildVsn() {
return this.generatorBuildVsn;
}
public void setGeneratorBuildVsn(String n) {
this.generatorBuildVsn = n;
}
public String getSeverity() {
return this.severity;
}
public void setSeverity(String n) {
this.severity = n;
}
public String getSubsystemID() {
return this.subsystemID;
}
public void setSubsystemID(String n) {
this.subsystemID = n;
}
public String getTaskID() {
return this.taskID;
}
public void setTaskID(String n) {
this.taskID = n;
}
public String getUniqueEventID() {
return this.uniqueEventID;
}
public void setUniqueEventID(String n) {
this.uniqueEventID = n;
}
}
The theme is the object sets the properties of javabean class and I have to get those values from UI.
In Jsp
<%
MessageBean consumer = msg.getMessages();
//Now here i want to iterate that consumer object
%>
As the MessagesBean seems to comply the javabeans specification, you can just use java.beans.Introspector for this.
MessageBean messageBean = consumerTool.getMessages();
// ...
BeanInfo beanInfo = Introspector.getBeanInfo(MessageBean.class);
for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
String name = property.getName();
Object value = property.getReadMethod().invoke(messageBean);
System.out.println(name + "=" + value);
}
This all is under the covers using the reflection API.
Update your edit reveals that you're intending to use this to present the data in JSP. This is then not really the right approach. Bite the bullet and specify every property separately. This way you've full control over the ordering.
Can someone tell me what the purpose of having inner classes? I can think of a few but may be they are not good reasons for using inner classes. My reasoning is that inner class is helpful when you want to use a class that no other classes can use. What else?
When I was learning Java we used inner classes for GUI event handling classes. It is sort of a "one time use" class that need not be available to other classes, and only is relevant to the class in which it resides.
Inner classes can be used to simulate closures: http://en.wikipedia.org/wiki/Closure_(computer_science)#Java
I use inner classes to define a structure that is best represented by the containing class, but doesn't necessarily make sense to use a separate external class to represent the structure.
To give an example I have a class that represents a particular type of network device, and the class has certain types of tests that can be run on that device. For each test there is also a potential set of errors that can be found. Each type of device may have a different structure for the errors.
With this you could do things like
List<Error> errors = RemoteDeviceA.getErrors();
With methods being available from the inner class, like
for ( Error error : errors ) {
System.out.println("MOnitor Type: " + error.getMonType());
...
}
Of course there are other ways to do this, this is just an inner class approach.
Simplified (aka incomplete) code for above:
public class RemoteDeviceA {
private String host;
private String user;
private String password;
private static List<Error> errors;
public RemoteDeviceA(String user, String host, String password) {
this.host = host;
this.user = user;
this.password = password;
login();
}
private void login() {
// Logs in
}
public void runTestA() {
List<Error> errorList = new ArrayList<Error>();
//loop through test results
if (!value.equals("0")) {
Error error = new Error(node, rackNum, shelfNum, slotNum, monType, value);
if (error.isError()) {
errorList.add(error);
}
}
setErrors(errorList);
}
private static void setErrors(List<Error> errors) {
RemoteDeviceA.errors = errors;
}
public List<Error> getErrors() {
return errors;
}
public class Error {
private String monType;
private String node;
private String rack;
private String shelf;
private String slot;
private String value;
private boolean error = false;
private boolean historyError = false;
private boolean critical = false;
private boolean criticalHistory = false;
Error(String node, String rack, String shelf, String slot,
String monType, String value) {
parseAlarm(node, rack, shelf, slot, monType, value);
}
private void parseAlarm(String node, String rack, String shelf,
String slot, String monType, String value) {
String modType = "";
if (monType.startsWith("ES_15") && !value.equals("0")) {
setMonType("ES_15");
setError(true);
} else if (monType.startsWith("SES_15") && !value.equals("0")) {
setMonType("SES_15");
setError(true);
} else if (monType.startsWith("BBE_15") && !value.equals("0")) {
setMonType("BBE_15");
setError(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(critical);
} else if (monType.startsWith("ES_24") && !value.equals("0")) {
setMonType("ES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("SES_24") && !value.equals("0")) {
setMonType("SES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("BBE_24") && !value.equals("0")) {
setMonType("BBE_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("UT_24") && !value.equals("0")) {
setMonType("UT_24");
setHistoryError(true);
setError(true);
setCriticalHistory(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(true);
} else if (monType.startsWith("LASPWR")) {
float laserPwr = Float.valueOf(value);
if (node.startsWith("LEM_EM")) {
if ((laserPwr < 8.0) || (laserPwr > 12.0)) {
setMonType("LASERPWR");
setError(true);
}
} else if (node.startsWith("LEM10")) {
if ((laserPwr < 18.0) || (laserPwr > 22.0)) {
setMonType("LASERPWR");
setError(true);
}
}
}
if (isError()) {
setNode(node);
setRack(rack);
setShelf(shelf);
setSlot(slot);
setValue(value);
setError(true);
}
}
private void setMonType(String monType) {
this.monType = monType;
}
public String getMonType() {
return monType;
}
private void setNode(String node) {
this.node = node;
}
public String getNode() {
return node;
}
public void setRack(String rack) {
this.rack = rack;
}
public String getRack() {
return rack;
}
public void setShelf(String shelf) {
this.shelf = shelf;
}
public String getShelf() {
return shelf;
}
public void setSlot(String slot) {
this.slot = slot;
}
public String getSlot() {
return slot;
}
private void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
private void setError(boolean error) {
this.error = error;
}
public boolean isError() {
return error;
}
public void setCritial(boolean critical) {
this.critical = critical;
}
public boolean isCritical() {
return critical;
}
public void setCriticalHistory(boolean criticalHistory) {
this.criticalHistory = criticalHistory;
}
public boolean isCriticalHistory() {
return criticalHistory;
}
public void setHistoryError(boolean historyError) {
this.historyError = historyError;
}
public boolean isHistoryError() {
return historyError;
}
}
}
A list implementation that internally uses a linked list to store the elements could make good use of an inner class to represent the nodes within the list. I think you've hit the nail on the head by saying that you'd use such a class where you want to use it internally to a class but don't want it exposed - a 'one off' class that is only really useful 'here'.
I use inner classes (in C++) in situations where multiple classes, unrelated through inheritance, have conceptually similar implementation details, which form an implicit part of the public interface and ought to be named similarly.
class lib::Identifier { ... };
class lib::Person {
public:
class Identifier : public lib::Identifier { ... };
};
class lib::File {
public:
class Identifier : public lib::Identifier { ... };
};
This makes it convenient to refer to Identifier, Person::Identifier, and File::Identifier as simply Identifier, in the appropriate scopes.