How to migrate Room database with ArrayList field? - java

There is an already created #Embedded class Player. I want to add to it the ArrayList field, which uses #TypeConverters, which converts my List to Gson when saving and back when loading.
Please tell me how to make a request in the void migrate ()
method to add the list to an already existing instance of the Player
class.
#Database(entities = {Save.class}, version = 2)
public abstract class AppDatabase extends RoomDatabase {
public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
#Override
public void migrate(final SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Save ADD COLUMN trainingPower
INTEGER DEFAULT 5 NOT NULL");
}
};
}
Player class:
public class Player
{
#TypeConverters({AlbumsListConverter.class})
private List<Albums> albumsList = new ArrayList();
#Embedded(prefix="energy_")
public Skills energy;
public int energyCount;
public int energyMax = 50;
public String fameName;
#Embedded(prefix="flow_")
public Skills flow;
public int imageID;
int imagePers;
#Embedded(prefix="mast_")
public Skills mastering;
#Embedded(prefix="mast2_")
public Skills mastering2;
private long money = 50;
#Embedded(prefix="music_")
public Skills music;
private String name;
public int ratingPosition = 1;
public int reclameToken = 0;
#TypeConverters({TrackListConverter.class})
public List<Tracks> releaseList = new ArrayList();
#TypeConverters({MessagesConverter.class})
public List<Massages> messagesList = new ArrayList<>();
private long reputation = 0;
private int respect = 1;
...
}
class Save:
#Entity
public class Save
{
#TypeConverters({ArrayConverter.class})
public String[] AllTopicTracks;
#Embedded
private Player actor;
...
}
TypeConverter:
public class MessagesConverter {
#TypeConverter
public String fromMassagesList(List<Messages> messages)
{
Gson gson = new Gson();
return gson.toJson(messages);
}
#TypeConverter
public List<Messages>toMessagesList(String data)
{
Gson gson = new Gson();
Type type = new TypeToken<List<Messages>>(){}.getType();
return gson.fromJson(data,type);
}
}

It seems you had used #Embedded for multiple variables. If #Embedded is annotated the variables of model class is treated as column for the same table. So for the case of multiple objects of same type you shoud use TypeConverter where the object can be converted to json string while saving and later retrieved as the object.
Instead of making embedded Player, create type converter for player and use it. By doing this you don't have to create separate type converter for objects inside player.

Related

Java different objects in a single method

I Know there are a bunch of questions related with this topic. Most of the answers states "use a interface" or "create a generic". Tried both and didnt work =( dont know what I'm doing wrong.
Here is the problem: I have two classes: Subjects and Courses. In the main section, I want a function that will receive an id (provided by the user) and look into, for example, a subjectList, trying to find if the subject is there, if yes , return its index. The logic is the same for both Courses and Subjects, so I'm trying to let this function become a bit more generic.
public static void main(String[] args) {
//Objects created along the code are stored here
ArrayList<Course> courseList = new ArrayList<>();
ArrayList<Subject> subjectList = new ArrayList<>();
public static Integer findObjectById(int id, ArrayList<IStudyDetails> object_list) {
for (int i = 0; i < object_list.size(); i++) {
if (id == object_list.get(i).getId()) {
return i;
}
}
return null;
}
int index_subject = findObjectById(subject_id,subjectList);
}
Here is the Interface:
I tried to create this after look into some Stack Overflow related topics.
public interface IStudyDetails{
int getId();
}
Here is the Course class: (I did hide most of the constructors/gets and setters)
public class Course implements IStudyDetails {
private int id;
private String name;
public int getId() {return id;}}
Here is the Subject class (I did hide most of the constructors/gets and setters)
public class Subject implements IStudyDetails {
private int id;
private String name;
public int getId() {return id;}}
THe error I'm receiving is:
java: incompatible types: java.util.ArrayList<entities.Subject> cannot
be converted to java.util.ArrayList<entities.IStudyDetails>
public static void main(String[] args) {
//Objects created along the code are stored here
List<IStudyDetails> courseList = new ArrayList<>();
List<IStudyDetails> subjectList = new ArrayList<>();
Subject subject = new Subject(0001, "John");
Subject subject1 = new Subject(1001, "Tom");
subjectList.add(subject);
subjectList.add(subject1);
int subject_id = 1001;
int index_subject = findObjectById(subject_id,subjectList);
}
public static Integer findObjectById(int id, List<IStudyDetails> object_list) {
for (int i = 0; i < object_list.size(); i++) {
if (id == object_list.get(i).getId()) {
System.out.println(i);
return i;
}
}
return null;
}
I Just change the List Type, Cause both Course and Subject are implemented from IStudyDetails, so you need to use IStudyDetails as a type to create the list and it can work.

Vaadin Table - AddNestedContainerProperty

public class LocationBasedRole extends AbstractEntity{
#ManyToMany(fetch=FetchType.LAZY)
private Set<Role> roles=new HashSet<Role>();
#ManyToMany(fetch=FetchType.LAZY)
private Set<Location> locations=new HashSet<Location>();
}
public class Role extends AbstractEntity{
private String name;
}
public class Location extends AbstractEntity{
private String location;
}
I have an entity named locationBasedRole which has 2 properties named roles and locations. Both roles and locations have a #ManyToMany relation with locationBasedRole.
Now I want to have one property of each in a Vaadin Table. It should be something like this,
public class UserForm extends OgsAbstractForm<User>{
MTable<LocationBasedRole> locationBasedRoleTable = new MTable<LocationBasedRole>().withHeight("100%").withWidth("100%");
#Override
protected Component createContent() {
Set<LocationBasedRole> lbRoles=new HashSet<LocationBasedRole>();
roles.addAll(locationBasedRoleFasade.findAll());
BeanItemContainer<LocationBasedRole> bean=new BeanItemContainer<LocationBasedRole>(LocationBasedRole.class);
//It returns an error on the next both lines and I know the reason, but don't know how to solve it.
// If it was no ManyToMany relation and the properties weren't a collection, it would work
bean.addNestedContainerProperty("roles.name");
bean.addNestedContainerProperty("locations.location");
bean.removeContainerProperty("persistent");
bean.removeContainerProperty("id");
bean.addAll(lbRoles);
locationBasedRoleTable.setContainerDataSource(bean);
return new VerticalLayout(locationBasedRoleTable);
}
}
When I remove the properties from the NestedContainerProperties it shows me at least something in the table.
bean.addNestedContainerProperty("roles");
bean.addNestedContainerProperty("locations");
I could use any help!
Thanks in advance!
So if I understand your question right, you want to have the Collections of your BeanItemContainer-Entity displayed in one column each?
I see two possibilities for that.
Option 1 - use a wrapper class for your Sets and use addNestedContainerBean
One possibility would be to not use Sets inside your LocationBasedRole but to use a wrapper class that extends HashSet.
Then you could use the addNestedContainerBean method.
I created a small example with the BeanItemContainer-Entity Team
public class Team {
private String teamName;
private Members teamMembers;
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
public Members getTeamMembers() {
return teamMembers;
}
public void setTeamMembers(Members teamMembers) {
this.teamMembers = teamMembers;
}
}
Which consists of a name and teamMembers. The latter is of type Members:
public class Members extends HashSet<TeamMember> {
public String getMembers() {
return this.stream()
.map(member -> member.getFirstName() + " " + member.getLastName())
.collect(Collectors.joining(","));
}
}
Which is a simple wrapper for the Set that contains instances of TeamMember:
public class TeamMember {
private String firstName;
private String lastName;
private Integer age;
// getters and setters
}
As you can see in the Members class, there is a method getMembers which returns a String, containing a comma separated list of the team members names.
If we now use addNestedContainerBean("teamMembers") Vaadin tries to display all properties contained in the class Members. Vaadin will think getMembers is a getter for a String property called members and so generate a column for it.
Vaadin will also display a column "empty" because it will find the isEmpty method of Set and think empty is a property to display in a column. So we tell Vaadin to remove that column.
The final code of my example looks like:
protected Component createContent() {
Set<Team> teams=new HashSet<>();
for (int teamCounter = 0; teamCounter < 5; teamCounter++) {
Team team = createTeam();
addMembersToTeam(5, team);
teams.add(team);
}
BeanItemContainer<Team> bean=new BeanItemContainer<>(Team.class);
bean.addNestedContainerBean("teamMembers");
bean.removeContainerProperty("teamMembers.empty");
bean.addAll(teams);
teamTable.setContainerDataSource(bean);
return new VerticalLayout(teamTable);
}
The result looks like:
Option 2 - create fake getters and use addNestedContainerProperty
The only thing you have to do for this is extend your BeanItemContainer-Entity (LocationBasedRole) and create a fake getter for each Set you want to be displayed in a column. In your example those two fake getters could be public String getTheRoles() and public String getTheLocations(). Then you can use bean.addNestedContainerProperty("theRoles") and bean.addNestedContainerProperty("theLocations").
In my example my TeamMember class (the counterpart to your Role / Location classes) would still look like in the option above:
public class TeamMember {
private String firstName;
private String lastName;
private Integer age;
// getters and setters
}
And my Team class (your LocationBasedRole) would look like:
public class Team {
private String teamName;
private Set<TeamMember> teamMembers;
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
public Set<TeamMember> getTeamMembers() {
return teamMembers;
}
public void setTeamMembers(Set<TeamMember> teamMembers) {
this.teamMembers = teamMembers;
}
public String getMembers() {
if (teamMembers != null) {
return teamMembers.stream()
.map(member -> member.getFirstName() + " " + member.getLastName())
.collect(Collectors.joining(","));
} else {
return "No members";
}
}
}
Now you can tell vaadin to add the (not existing) property "members" and Vaadin will find the getter getMembers and use this for generating the column. We also have to tell vaadin not to display the original "teamMembers" property. So the final code is:
protected Component createContent() {
Set<Team> teams=new HashSet<>();
for (int teamCounter = 0; teamCounter < 5; teamCounter++) {
Team team = createTeam();
addMembersToTeam(5, team);
teams.add(team);
}
BeanItemContainer<Team> bean=new BeanItemContainer<>(Team.class);
bean.addNestedContainerProperty("members");
bean.removeContainerProperty("teamMembers");
bean.addAll(teams);
teamTable.setContainerDataSource(bean);
return new VerticalLayout(teamTable);
}
and the result looks like:

Java how to generate and assign attributes to an Object in an efficient way?

I'm building an automation testing program, I'd like it to have ability to generator fake customer data. To do that, I've done things like:
- Created a Customer Object which has 40 variables
- Created a GustGenerator Class to generate faker data and assign to Customer object.
//Customer object class
public class Customer {
public static final String EMAIL = "user.name#******.com";
public static final String PHONE = "0956***2001";
public static final String LAS_NAME = "Owen";
public static final String FIN_PURP_TYPE = "ELP";
public static final String ADDRESS = "User Address";
private String title;
private String firName;
private String midName;
private boolean isReqMet;
private int media;
...... 40 attributes in total.
...... getters and setters
}
//Fake customer data generator.
public class CustGenerator {
private Customer customer;
private Faker faker = new Faker();
private Customer firstName(Customer customer) {
customer.setFirName(faker.name().firstName());
return customer;
}
private Customer midName(Customer customer) {
customer.setMidName(faker.name().lastName());
return customer;
}
......Generate data one by one.
}
My question is is there a better way to construct this feature? More simple and more efficiency. Any input is appreciated. Thank you very much.
You can do it by creating a constructer function in your customer class:-
Public class Customer{
...create variables
Public Customer(bool random){
If(random){
//generate variables randomly
}else{
//initiallize what do you want
}
}
}
And also i suggest if parameters is such more create a dictionary instead of creating a lot of variables, for e.g:-
Dictionary<string, object> vals = new Dictionary<string, object>();
And if you just use string values so make second parameter to string.

Dimanic Model in Java

I'm making a contacts app, this is my model.
public class Contact {
private RelationShip relationShip;
public static class RelationShip {
private Friend friend;
private Enemie enemie;
private Family family;
private class Family {
private Brother brother;
private Sister sister;
}
}
}
I want to create it you can do it the way suiguiente.
RelationShip realation = new RelationShip(RelationShip.Friend);
Contact contact = new Contact(realation);
I want to establish the kind of relationship in a variable. Really do not know how to ask the question. an example would be something like this:
layout.setOrientation (LinearLayout.VERTICAL);
LinearLayout.VERTICAL is a constant or an enumerate. Take a look here for example.
To achieve the same behavior in your code set those values as constants (usually int).
public static class RelationShip {
public static final int FRIEND = 0;
public static final int ENEMIE = 1;
public static final int FAMILY = 2;
...
}
public class Contact {
private int relationshipType;
...
public void setRelationShipType(int relationShip) {
}
public boolean areWeFriends() {
if (relationshipType==Relationship.FRIEND)
return true;
else
return false;
}
...
}
You can then set the relationship setRelationShipType(Relationship.FRIEND). Or check if the relationship of Contact HerryPotter is a friend with HarryPotter.areWeFriends()
EDIT:
Actually the correct way is indeed the one suggested by alfasin: using enumerates.
public enum RelationShip {
FRIEND, ENEMIE, FAMILY
}
public class Contact {
private RelationShip relationshipType;
public void setRelationShipType(RelationShip relationShip) {
...
}
public boolean areWeFriends() {
if (relationshipType==Relationship.FRIEND)
return true;
else
return false;
}
}

Cast base class to inherited class from deserialized collection in java

I have a base class
SocialRecord.java
public class SocialRecord{
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
and two derived classes
SocialEmailRecord.java
public class SocialEmailRecord extends SocialRecord{
private String subject;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
SocialDiscussionRecord.java
public class SocialDiscussionRecord extends SocialRecord{
private String source;
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
}
I create some instances of SocialEmailRecord and SocialDiscussionRecord classes.
SocialEmailRecord r1 = new SocialEmailRecord();
r1.setSubject("sub1");
SocialEmailRecord r2 = new SocialEmailRecord();
r2.setSubject("sub2");
SocialDiscussionRecord r3 = new SocialDiscussionRecord();
r3.setSource("source3");
SocialDiscussionRecord r4 = new SocialDiscussionRecord();
r4.setSource("source4");
I add these objects to a collection.
List<SocialRecord> records = new ArrayList<>(Arrays.asList(r1, r2, r3, r4));
I serialize this collection by gson.
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String objsInJson = gson.toJson(records);
Now I would like to deserialize this collection, but I don't know how to construct original objects of collection.
Type listType = new TypeToken<ArrayList<Object>>() {}.getType();
List records = new ArrayList<>(Arrays.asList(graphUtils.getGson().fromJson(objsInJson), listType)));
I tried this, but it doesn't work.
for (int i = 0; i < records.size(); i++){
if (records.get(i).getClass().equals(SocialDiscussionRecord.class))
records.set(i, (SocialDiscussionRecord) records.get(i));
if (records.get(i).getClass().equals(SocialPhoneRecord.class))
records.set(i, (SocialPhoneRecord) records.get(i));
if (records.get(i).getClass().equals(SocialEmailRecord.class))
records.set(i, (SocialEmailRecord) records.get(i));
if (records.get(i).getClass().equals(SocialRecord.class))
records.set(i, (SocialRecord) records.get(i));
}
You will have to implement a TypeHierarchyAdapter and register it to the GsonBuilder that will manage the deserialisation of the specificities of each subclass.
See here for a full classical example with Employee/Manager
But then you will get an ArrayList<SocialRecord> even if the object instances are actual SocialEmailRecord or SocialDiscussionRecord. You need to define some methods in SocialRecord that shall be overridden in the subclasses and use polymorphism to process the list.

Categories