Selecting the option passed from the controller - spring-mvc

I'm having trouble with the selection of the right value in a 'select' when the options are String. I can't find the solution in the forums.
I pass 'kind' in the controller and I can see that the values are fine but only the Integer fields are selected properly in the 'select'. The ones with String always show the first value and not the one pass in 'kind'.
I added the code I thought it could help
Can anyone help?
My HTML code. The form contains many 'select' but I left two, the first one works but the second one always show the first option:
<form role="form" th:action="#{/kind/update}" th:object="${kind}" method="post">
<div class="form-group col-md-4">
<label for="replicates">No. of Replicates</label>
<select id="replicates" class="form-control" style="width: 70%;" th:field="${kind.replicates}">
<option th:each="rep: ${replicatesnumber}" th:value="${rep}" th:text="${rep}"> </option>
</select>
</div>
<div class="form-group col-md-3">
<label for="substrate">Substrate</label>
<select id="substrate" class="form-control" th:field="${kind.substrate}">
<option th:each="substrate: ${substrates}" th:value="${substrate}" th:text="${substrate}"> </option>
</select>
</div>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Save</button>
<a class="btn btn-primary" th:href="#{/division/edit/}+${kind.division.id}" role="button">Cancel</a>
</div>
</form>
The controller look like this:
#Controller
#RequestMapping("/kind")
public class KindController {
#Autowired
private KindService kindService;
#ModelAttribute("replicatesnumber")
public int[] getReplicates() {
int[] reps = new int[3];
reps[0] = 2;
reps[1] = 4;
reps[2] = 8;
return reps;
}
#ModelAttribute("substrates")
public List<String> getSubstrates() {
return Arrays.asList("BP", "PP", "TP", "OGM", "Sand");
}
#GetMapping(value= "/edit/{kindId}")
public String viewDivision(#PathVariable Integer kindId, Model model){
Kind kind= kindService.findById(kindId);
model.addAttribute("kind",kind);
return "kind_edit";
}
and the entity:
#Entity
#Table(name = "kind", schema = "ostscourses")
public class Kind implements java.io.Serializable {
private Integer id;
private Division division;
private String name;
private Integer germinationDays;
private Integer firstCount;
private Integer replicates;
private Boolean dark;
private Integer chill;
private String temperature;
private String substrate;
private Integer noSeeds;
private List<Sample> samples;
public Kind() {
}
public Kind(Integer id, Division division) {
this.id = id;
this.division = division;
}
public Kind(Integer id, Division division, String name, Integer germinationDays, Integer firstCount, Integer replicates, Boolean dark, Integer chill, String temperature, String substrate, Integer noSeeds, List<Sample> samples) {
this.id = id;
this.division = division;
this.name = name;
this.germinationDays = germinationDays;
this.firstCount = firstCount;
this.replicates = replicates;
this.dark = dark;
this.chill = chill;
this.temperature = temperature;
this.substrate = substrate;
this.noSeeds = noSeeds;
this.samples = samples;
}
#Id
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "division_id", nullable = false)
#JsonIgnore
public Division getDivision() {
return this.division;
}
public void setDivision(Division division) {
this.division = division;
}
#Column(name = "name", length = 25)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "germination_days")
public Integer getGerminationDays() {
return this.germinationDays;
}
public void setGerminationDays(Integer germinationDays) {
this.germinationDays = germinationDays;
}
#Column(name = "first_count")
public Integer getFirstCount() {
return this.firstCount;
}
public void setFirstCount(Integer firstCount) {
this.firstCount = firstCount;
}
#Column(name = "replicates")
public Integer getReplicates() {
return this.replicates;
}
public void setReplicates(Integer replicates) {
this.replicates = replicates;
}
#Column(name = "dark")
public Boolean getDark() {
return this.dark;
}
public void setDark(Boolean dark) {
this.dark = dark;
}
#Column(name = "chill")
public Integer getChill() {
return this.chill;
}
public void setChill(Integer chill) {
this.chill = chill;
}
#Column(name = "temperature", length = 10)
public String getTemperature() {
return this.temperature;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
#Column(name = "substrate", length = 5)
public String getSubstrate() {
return this.substrate;
}
public void setSubstrate(String substrate) {
this.substrate = substrate;
}
#Column(name = "no_seeds")
public Integer getNoSeeds() {
return this.noSeeds;
}
public void setNoSeeds(Integer noSeeds) {
this.noSeeds = noSeeds;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "kind")
#JsonIgnore
public List<Sample> getSamples() {
return this.samples;
}
public void setSamples(List<Sample> samples) {
this.samples = samples;
}
#Override
public int hashCode() {
int hash = 3;
hash = 47 * hash + Objects.hashCode(this.id);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Kind other = (Kind) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Kind{" + "id=" + id + ", name=" + name + ", germinationDays=" + germinationDays + ", firstCount=" + firstCount + ", replicates=" + replicates + ", dark=" + dark + ", chill=" + chill + ", temperature=" + temperature + ", substrate=" + substrate + ", noSeeds=" + noSeeds + '}';
}
}

Well, I just found a solution creating enum with the values I need in the select
public enum SubstrateType{
BP,
PP,
TP,
OGM,
Sand;
}
In my controller:
#ModelAttribute("substrates")
public SubstrateType[] getSubstrates() {
return SubstrateType.values();
}
I know it should work without enum as I have seen this before. Anyway I think is a good practice having enum.

Related

Filter based on user input - LiveData, Recycler, RoomView

I have an SQLite Database for my Android App. Database has a table for properties , and another table for the repairs at each property.
Table repairs :
#Entity(tableName = "repairs",
indices = {#Index(value = "repairID", unique = true), #Index("repairPropID")})
public class MYRepairs
{
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "repid")
public int id;
#ColumnInfo(name = "repairID")
#NonNull
public String repairID;
#ColumnInfo(name = "repairPropID")
public int repairPropID;
}
...
and then RepairsDao.java
#Dao
public interface MyRepairsDao
{
#Query("SELECT * FROM repairs WHERE repid = :repid LIMIT 1")
MYRepairs findRepairById(String repid);
#Query("SELECT * FROM repairs WHERE repairPropID = :repairPropID")
MYRepairs findRepairByPropID(int repairPropID);
#Query("SELECT * FROM repairs ORDER BY repairPropID ASC")
LiveData<List<MYRepairs>> getAllRepairs();
#Query("SELECT * FROM repairs WHERE repairPropID = :repairPropID")
LiveData<List<MYRepairs>> getPropertyRepairs(int repairPropID);
}
In the ViewModel:
public class repairViewModel extends AndroidViewModel
{
private MyRepairsDao myRepairDao;
private LiveData<List<MYRepairs>> repairLiveData;
private LiveData<List<MYRepairs>> repairPropertyLiveData;
private LiveData<String> filterLiveData = new MutableLiveData<String>();
public repairViewModel(#NonNull Application application)
{
super(application);
myRepairDao = DogwoodDatabase.getDatabase(application).repairDao();
repairLiveData = myRepairDao.getAllRepairs();
repairPropertyLiveData = myRepairDao.getPropertyRepairs(propertyID);
}
public LiveData<List<MYRepairs>> getAllRepairs()
{
return repairLiveData;
}
public LiveData<List<MYRepairs>> getPropertyRepairs(int propertyID)
{
return repairPropertyLiveData;
}
And in the RecyclerView.Adapter:
public class repairListAdapter extends RecyclerView.Adapter<repairListAdapter.RepairViewHolder>
{
#NonNull
#Override
public repairListAdapter.RepairViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
final View itemView = layoutInflater.inflate(R.layout.repaircontent, parent, false);
return new repairListAdapter.RepairViewHolder(itemView);
}
In the repairFragment - we only want to view the repairs for a user selected property. Property Code propertyID is received by the repairFragement. It is known to the initData()
public class repairFragment extends Fragment
{
private repairListAdapter repairListAdapter;
private repairViewModel repairViewModel;
public void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
propertyID = getArguments().getString("ARG_PROPNUM_ID");
propNumID = Integer.parseInt(propertyID);
initData();
}
private void initData()
{
Log.e ("INIT", "ID is " + propertyID);
repairViewModel = new
ViewModelProvider(this).get(repairViewModel.class);
repairViewModel.getPropertyRepairs(propertyID).observe(this, new Observer<List<MYRepairs>>()
{
#Override
public void onChanged(#Nullable List<MYRepairs> MYRepairs)
{
repairListAdapter.setMYRepairList(MYRepairs);
}
});
}
This returns NO RECORDS.
In an ideal world, my properties would have no repairs, but I do not live in that world!
I have scoured this board for help on filtering .
Can you help me with how to filter for only the repairs for a user selected property (propertyID).
Thanks, Rachael
What you wanted to do is the following:
public LiveData<List<MYRepairs>> getPropertyRepairs() {
return repairPropertyLiveData;
}
And
private MutableLiveData<String> selectedPropertyId = new MutableLiveData<>();
private final repairPropertyLiveData = Transformations.switchMap(selectedPropertyId, (id) -> {
return myRepairDao.getPropertyRepairs(id);
});
public void updateSelectedProperty(String propertyId) {
selectedPropertyId.setValue(propertyId);
}
This way, you don't end up with new subscriptions that were not properly invalidated in case you were to select a different property id later.
Oh my! I figured it out.
In repairViewModel:
public LiveData<List<MYRepairs>> getPropertyRepairs(int propertyID)
{
repairPropertyLiveData = myRepairDao.getPropertyRepairs(propertyID);
return repairPropertyLiveData;
}

How do i correctly loop through the my list to display the information using Razor?

I have been struggling to loop through my private static List in my HomeController to display in such a way it shows a list of both students and personnel. Below is an example of what my loop should look like.
[Student] Name:John Surname:Greenberg Email: 123#123 Cellphone:123456789 Age: 20
[Personnel] Name:Rose Surname:Marry Email: email#email Cellphone:123456789 WorkerType: Permanent Degree: BED Education
[Student] Name:Chaz Surname:Brown Email: chazz#gmail.com Cellphone:123456789 Age: 30
Please help me loop properly and Below is my ContestantView i tried coding
#model List<Assignment9_u14333393.Models.ContestantViewModel>
<div style="width:100%;height:auto; background-color:brown; padding-top:10px; padding-bottom:10px;">
<h2 style="text-align:center; color:white;">List of Contestants</h2>
</div>
.
<div class="members" >
<table>
#foreach (var temp in Model)
{
<div class="member">
[#temp.MemberType] Name:#temp.Name Surname:#temp.Surname Email: #temp.Email Cellphone:#temp.CellPhone
</div>
}
</table>
</div>
For additional information I also have three models (StudentViewModel, PersonnelViewModel and ContestantViewModel).
ContestantViewModel is my parent class and StudentViewModel and PersonnelViewModel are my classes which have inherited data members and properties for the parent class.
1st Model
public class ContestantViewModel
{
//Data members
private string mName;
private string mSurname;
private string mCellPhone;
private string mEmail;
private string mMemberType;
//Defeaut Constructor
public ContestantViewModel()
{
mName = "NoName";
mSurname = "NoSurname";
mCellPhone = "NoCellNumber";
mEmail = "NoEmail";
mMemberType = "NoMemberType";
}
//Constructor
public ContestantViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType)
{
mName = Name;
mSurname = Surname;
mCellPhone = CellPhone;
mEmail = Email;
mMemberType = MemberType;
}
//Properties
public string Name
{
get { return mName; }
set { mName = value; }
}
public string Surname
{
get { return mSurname; }
set { mSurname = value; }
}
public string CellPhone
{
get { return mCellPhone; }
set { mCellPhone = value; }
}
public string Email
{
get { return mEmail; }
set {mEmail = value; }
}
public string MemberType
{
get; set;
}
}
2rd Model
public class PersonnelViewModel : ContestantViewModel
{
private string mWorkerType;
private string mDegree;
public PersonnelViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType, string WorkerType, string Degree) : base (Name,Surname,CellPhone,Email, MemberType)
{
mWorkerType = WorkerType;
mDegree = Degree;
}
public PersonnelViewModel()
{
mWorkerType = "NoWorkerType";
mDegree = "NoDegree";
}
public string WorkerType
{
get { return mWorkerType;}
set { mWorkerType = value; }
}
public string Degree
{
get { return mDegree; }
set { mDegree = value; }
}
}
3rd Model
public class StudentViewModel : ContestantViewModel
{
//Data members
private int mAge;
//D Constructor
public StudentViewModel()
{
mAge = 0;
}
//Constructor
public StudentViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType, int Age) : base(Name, Surname, CellPhone, Email, MemberType)
{
mAge = Age;
}
//properties
public int Age
{
get { return mAge; } set { mAge = value; }
}
}
and this is my controller
public class HomeController : Controller
{
// list to hold all my new members
private static List<ContestantViewModel> List = new List<ContestantViewModel>();
// GET: Home
public ActionResult Index()
{
return View();
}
// GET: Signup
public ActionResult Signup(string Name, string Surname, string Email, string Cellphone, string MemberType, int Age,string WorkerType,string Degree)
{
StudentViewModel Stundent = new StudentViewModel();
PersonnelViewModel Personnel = new PersonnelViewModel();
if (MemberType == "Student")
{
//creates instance
Stundent.Name = Name;
Stundent.Surname = Surname;
Stundent.Email = Email;
Stundent.CellPhone = Cellphone;
Stundent.MemberType = MemberType;
Stundent.Age = Age;
// Add data to list
List.Add(Stundent);
}
else
{
//creates instance
Personnel.Name = Name;
Personnel.Surname = Surname;
Personnel.Email = Email;
Personnel.CellPhone = Cellphone;
Personnel.MemberType = MemberType;
Personnel.WorkerType = WorkerType;
Personnel.Degree = Degree;
// Add data to list
List.Add(Personnel);
}
return View(List);
}
}
Put your collection into it's own view model instead of trying to reference it with this line:
#model List<Assignment9_u14333393.Models.ContestantViewModel>
Make a new view model, ViewModelCollections with a collection of your ContestantViewModel. Something like
List<ContestantViewModel> ContestantList
(you can also add others, like your students and workers and reuse the model, even if for some purposes some collections are empty)
Then reference that with:
#model ViewModelCollections
Once you have put all your contestants into the collection you are very close in your current view code.
<div class="members">
<table id="contestantListTable">
<tbody>
#* Column Headers *#
<tr class="contestantListHeaders">
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
#* Content Rows *#
#foreach (var temp in Model.ContestantList)
{
<tr>
<td>#temp.mName</td>
<td>#temp.mSurName</td>
<td>#temp.mEmail</td>
<td>#temp.mCellPhone</td>
</tr>
}
</tbody>
</table>
</div>
Instead of this saying "Name: Contestant" "LastName: #1" etc etc
You will have a table:
First Name | Last Name | Email etc etc
Contestant | #1 | ...
.
.
.

Form Gives 400 Bad Request error when using with Spring's ModelAttribute

i have html form which i forward to spring controller. Its works fine if i use getParameter but using modelAttribute it says 400 bad request error.
Here is my controller Code
#Controller
public class BookController {
#RequestMapping (value="/addBook")
public String addBook(#ModelAttribute Book book){
System.out.println(book.getBookName());
bookService.addBooks(book);
return "index";
}
}
This is Book model Code
#Entity
#Table (name = "Book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID",columnDefinition = "BIGINT NOT NULL AUTO_INCREMENT")
private long bookId;
#Column(name="book_code",columnDefinition = "VARCHAR(200) NOT NULL")
private String bookCode;
private String bookName;
private String author;
#Temporal (TemporalType.DATE)
private Date dateOfArrival;
private Double price;
private String rackNo;
private int numberOfBook;
private String subjectCode;
public Book() {
super();
}
public Book(String bookCode, String bookName, String author,
Date dateOfArrival, Double price, String rackNo,
int numberOfBook, String subjectCode) {
super();
this.bookCode = bookCode;
this.bookName = bookName;
this.author = author;
this.dateOfArrival = dateOfArrival;
this.price = price;
this.rackNo = rackNo;
this.numberOfBook = numberOfBook;
this.subjectCode = subjectCode;
}
public String getBookCode() {
return bookCode;
}
public long getBookId() {
return bookId;
}
public void setBookId(long bookId) {
this.bookId = bookId;
}
public void setBookCode(String bookCode) {
this.bookCode = bookCode;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getDateOfArrival() {
return dateOfArrival;
}
public void setDateOfArrival(Date dateOfArrival) {
this.dateOfArrival = dateOfArrival;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getRackNo() {
return rackNo;
}
public void setRackNo(String rackNo) {
this.rackNo = rackNo;
}
public int getNumberOfBook() {
return numberOfBook;
}
public void setNumberOfBook(int numberOfBook) {
this.numberOfBook = numberOfBook;
}
public String getSubjectCode() {
return subjectCode;
}
public void setSubjectCode(String subjectCode) {
this.subjectCode = subjectCode;
}
}
I have doubt that the problem is due to using date
Please Help me out
I would try 2 things.
In your Model add this:
//here use the same pattern of date your send from the view
#DateTimeFormat(pattern = "dd/MM/yyyy")
private Date dateOfArrival;
In your controller
#RequestMapping (value="/addBook")
public String addBook(#ModelAttribute Book book, BindingResult result){
...
Then you will be able to debug your method and know the problem.

Javafx Custom TableCell

I have tables with editable fields item,Description,Quantity,Unit price and Sub Total.
I am creating a cellFactory and Column Update like this:
TableColumn DescriptionCol = new TableColumn("Description");
EditableTableSupport.createEditingColumn(DescriptionCol,"description");
TableColumn QuantityCol = new TableColumn("Quantity");
EditableTableSupport.createEditingColumn(QuantityCol,"quantity");
TableColumn UnitPriceColumn = new TableColumn<>("Unit Price");
EditableTableSupport.createEditingColumn(UnitPriceColumn,"unitPrice");
TableColumn DiscountColumn = new TableColumn<>("Discount");
EditableTableSupport.createEditingColumn(DiscountColumn,"discount");
SubTotalColumn = new TableColumn<>("SubTotal");
EditableTableSupport.createColumn(SubTotalColumn,"subTotal");
TableColumn SubTotalColumn = new TableColumn<>("SubTotal");
EditableTableSupport.createColumn(SubTotalColumn,"subTotal");
DescriptionCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String> t) {
((DUMMY_PurchaseOrderLine) t.getTableView().getItems().get(t.getTablePosition().getRow())).setDescription(t.getNewValue());
}
});
QuantityCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String> t) {
((DUMMY_PurchaseOrderLine) t.getTableView().getItems().get(t.getTablePosition().getRow())).setQuantity(t.getNewValue());
}
});
UnitPriceColumn.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String> t) {
((DUMMY_PurchaseOrderLine) t.getTableView().getItems().get(t.getTablePosition().getRow())).setUnitPrice(t.getNewValue());
}
});
DiscountColumn.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<DUMMY_PurchaseOrderLine, String> t) {
((DUMMY_PurchaseOrderLine) t.getTableView().getItems().get(t.getTablePosition().getRow())).setDiscount(t.getNewValue());
}
});
public class EditableTableSupport {
public static void createEditingColumn(TableColumn Column ,String name){
Callback<TableColumn, TableCell> cellFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
Column.setSortable(false);
Column.setCellValueFactory(new PropertyValueFactory<DUMMY_PurchaseOrderLine, String>(name));
Column.setCellFactory(cellFactory);
}
public static void createColumn(TableColumn Column, String name) {
Column.setSortable(false);
Column.setCellValueFactory(new PropertyValueFactory<DUMMY_PurchaseOrderLine, String>(name));
}}
Question:How to Update Subtotal Column When i updating Quantity Column or UnitPrice Column
Thank you..
public class DUMMY_PurchaseOrderLine {
private String name;
private String description;
private BigDecimal quantity;
private BigDecimal unitPrice;
private BigDecimal discount;
private BigDecimal subTotal;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getQuantity() {
return quantity;
}
public void setQuantity(BigDecimal quantity) {
this.quantity = quantity;
}
public BigDecimal getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(BigDecimal unitPrice) {
this.unitPrice = unitPrice;
}
public BigDecimal getDiscount() {
return discount;
}
public void setDiscount(BigDecimal discount) {
this.discount = discount;
}
public BigDecimal getSubTotal() {
return subTotal;
}
public void setSubTotal(BigDecimal subTotal) {
this.subTotal = subTotal;
}
public DUMMY_PurchaseOrderLine(String name, BigDecimal description, BigDecimal quantity,BigDecimal unitPrice,BigDecimal discount,BigDecimal subTotal) {
this.name = name;
this.description = description;
this.quantity = quantity;
this.unitPrice = unitPrice;
this.discount = discount;
this.subTotal = quantity.multiply(unitPrice).subtract(discount);
}
}
In your DUMMY_PurchaseOrderLine class create a read only property named subTotal and initialize it in the constructor via binding. The combination of the binding and the PropertyValueFactory you use to set the value for the SubTotalColumn will ensure that the correct subtotal is always reflected.
class DUMMY_PurchaseOrderLine {
private IntegerProperty quantity = new SimpleIntegerProperty(0);
private DoubleProperty unitPrice = new SimpleDoubleProperty(0);
private DoubleProperty discount = new SimpleDoubleProperty(0);
private ReadOnlyDoubleWrapper subTotal = new ReadOnlyDoubleWrapper(0);
DUMMY_PurchaseOrderLine() {
subTotal.bind(quantity.multiply(unitPrice).subtract(discount));
}
IntegerProperty quantityProperty() { return quantity; }
IntegerProperty unitPriceProperty() { return unitPrice; }
IntegerProperty discountProperty() { return discount; }
ReadOnlyDoubleProperty subTotalProperty() { return subTotal.getReadOnlyProperty(); }
}
Note the naming conventions used. Using the correct naming convention is key.
I'm assuming here that the subtotal is just the calculated value for a single row (specifically by quantity * unitPrice - discount), not a total of values calculated across multiple rows (which would be quite a difficult problem to solve with a TableView).
Update based on question edit
I see from your update that you are using BigDecimal and JavaFX doesn't have a corresponding BigDecimalProperty, so either you will need to create one (not trivial if you want it to be fully featured) or use one of the existing property types.
Your alternate to using properties is to use the low level binding api to calculate subtotals, but I'd advise using properties if you can.

Persisting interfaces using JDO/Datanucleus

I have the following class:
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class TclRequest implements Comparable<TclRequest> {
#PrimaryKey
private String id;
#Persistent(types = { DNSTestData.class, POP3TestData.class, PPPoETestData.class, RADIUSTestData.class }, defaultFetchGroup = "true")
#Columns({ #Column(name = "dnstestdata_fk"), #Column(name = "pop3testdata_fk"), #Column(name = "pppoetestdata_fk"), #Column(name = "radiustestdata_fk") })
private TestData testData;
public String getId() {
return id;
}
public TestData getTestData() {
return testData;
}
public void setId(String id) {
this.id = id;
}
public void setTestData(TestData testData) {
this.testData = testData;
}
}
The TestData interface looks like this:
#PersistenceCapable(detachable = "true")
public interface TestData {
#PrimaryKey
public String getId();
public void setId(String id);
}
Which is implemented by many classed including this one:
#PersistenceCapable(detachable = "true")
public class RADIUSTestData implements TestData {
#PrimaryKey
private String id;
private String password;
private String username;
public RADIUSTestData() {
}
public RADIUSTestData(String password, String username) {
super();
this.password = password;
this.username = username;
}
#Override
public String getId() {
return id;
}
#Override
public void setId(String id) {
this.id = id;
}
}
When I try to persiste the TclRequest class, after constructing it of course and using the RADIUSTestData:
//'o' is the constructed TclRequest object.
PersistenceManager pm = null;
Transaction t = null;
try {
pm = getPM();
t = pm.currentTransaction();
t.begin();
pm.makePersistent(o);
t.commit();
} catch (Exception e) {
e.printStackTrace();
if (t != null && t.isActive()) {
t.rollback();
}
} finally {
closePM(pm);
}
The interface field isn't persisted. And the column is not created in the table ! I enabled the debug mode and found 2 catchy things:
1)
-Class com.skycomm.cth.beans.ixload.radius.TestData specified to use "application identity" but no "objectid-class" was specified. Reverting to javax.jdo.identity.StringIdentity
2)
-Performing reachability on PC field "com.skycomm.cth.beans.TclRequest.testData"
-Could not find StateManager for PC object "" at field "com.skycomm.cth.beans.TclRequest.testData" - ignoring for reachability
What could this mean ?
Thanks in advance.
I have figured out how to do it. It's not very much scalable but it works for now.
These are the annotations for the interface member variable. Note that the order of declared types, columns and class names in the extension value is important to be maintaned:
#Persistent(types = { RADIUSTestData.class, POP3TestData.class, PPPoETestData.class, DNSTestData.class }, defaultFetchGroup = "true")
#Columns({ #Column(name = "radiustestdata_fk"), #Column(name = "pop3testdata_fk"), #Column(name = "pppoetestdata_fk"),
#Column(name = "dnstestdata_fk") })
#Extension(vendorName = "datanucleus", key = "implementation-classes", value = "com.skycomm.cth.tcl.beans.radius.RADIUSTestData, com.skycomm.cth.tcl.beans.pop3.POP3TestData, com.skycomm.cth.tcl.beans.pppoe.PPPoETestData, com.skycomm.cth.tcl.beans.dns.DNSTestData")
A sample class implementing one of the interfaces (Just it's "header"):
#PersistenceCapable(detachable = "true")
public class RADIUSTestData implements TestData {
So it's pretty normal here.

Resources