JavaFX ComboBox<POJO> Not updating values - java

After hours searching for an answer, finally I give up on this.
I have an FXML form with the following ComboBox:
<ComboBox fx:id="cboTipo" disable="true" prefWidth="247.0" promptText="Tipo de obra..." GridPane.columnIndex="1" GridPane.rowIndex="2" />
Which is injected in a JavaFX controller class:
#FXML
public ComboBox<Tobra> cboTipo;
The combo shows a list of Tobra (stands for: Tipo de Obra in spanish) loaded from an embedded H2 database using Eclipselink 2.7 and JPA 2.2.
I don't show to the user the value of Tobra.toString, instead I set a converter in the initialization:
#Override
public void initialize(URL url, ResourceBundle rb) {
...
Objects.requireNonNull(cboTipo, "cboTipo not injected");
...
cboTipo.setConverter(new StringConverter<Tobra>() {
#Override
public String toString(Tobra object) {
return object.getCod() + ": " + object.getNombre();
}
#Override
public Tobra fromString(String string) {
return new Tobra(string);
}
});
...
}
I have an inner class which implements Task<List<Tobra>> So I can load the data in background. Then, on succeeded:
task.setOnSucceeded(evt ->
cboTipo.setItems(FXCollections.observableArrayList(task.getValue()))
);
Of course, when showing the form I run the task inside a Thread:
new Thread(task).start();
Everything seems to work fine until the code is tested. No matters on what value I click, ALWAYS the selected value resets to the first item. I've tried to force some value from the code, and it shows up in the combobox, but when user clicks the combo to choose another value, again the selected value is reset to "first item".
This behavior only occurs when using a ComboBox with type parameters. When I create the combobox without type parameter, and then I add String values, something like this:
cboTipo.getItems().clear();
cboTipo.getItems().addAll(
tobraList.stream().map(x
-> x.getCod() + ": " + x.getNombre())
.toArray());
Everything works fine.
So I've tried doing the same with my POJO Tobra without mapping to string:
cboTipo.getItems().clear();
cboTipo.getItems().addAll(tobraList);
But the issue reappears. I've also tried declaring ComboBox cboTipo without type parameter but it neither works.
My POJO Tobra, overrides the equals method this way:
#Override
public boolean equals(Object object) {
if (!(object instanceof Tobra)) {
return false;
}
var other = (Tobra) object;
return ((this.cod == null && other.cod != null)
|| (this.cod != null && !this.cod.equals(other.cod)));
}
What am I doing wrong?
PS:
I also tried setting up my own cell factory as suggested in:
Javafx combobox with custom object displays object address though custom cell factory is used
And trying and debugging it I realized that the problem isn't the rendering of the component because the value property of ComboBox never gets updated after selection.

Your equals() method is weird.
return ((this.cod == null && other.cod != null)
|| (this.cod != null && !this.cod.equals(other.cod)));
Let's break this up. Part 1:
(this.cod == null && other.cod != null)
If cod of this Tobra is null and the cod of the other Tobra is not null, then this part is true.
Now the whole expression returns true when this happens, because you have a || operator.
Let's look at the second part.
(this.cod != null && !this.cod.equals(other.cod))
If cod of this Tobra is not null and the cod of the other Tobra are not equal, then this part is true.
This, again, looks reverse.
Most likely you need to ! the whole expression. Alternatively, you can use Objects.equals(this.cod, other.cod), which checks null for you.
Lastly, make sure you also override hashCode() and return a correct value that does not break the contract for equals(). Read the Javadoc for more details.

I solved the issue changing the equals method this way:
#Override
public boolean equals(Object object) {
if (object == null || !getClass().isAssignableFrom(object.getClass())) {
return false;
} else {
var other = (Tobra) object;
return Objects.equals(this.cod, other.cod);
}
}
Lesson: don't ever trust the autogenerated code.

Related

Is it Possible to Check Received fields are Empty or Null Without If

I am receiving list of fields. Near About to 60 fields.
From that I have to check 50 fields that are they null or empty, if not then I ll have to add them also in DB table.
Right now I am doing it manually using if condition. I am just thinking to do so, not implemented still yet.
Is there any better option then it ?
My Code :
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionStartYear())){
}
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionPeriod())){
}
if(ValidateData.checkIsNullOrEmpty(command.getExpectedArrivalTimeOfIssues())){
}
.....
.....
if(ValidateData.checkIsNullOrEmpty(command.getMaxNoOfClaims())){
}
Here command is class which receives Data from source.
Here ValidateData is a class :
It's method definition :
public static boolean checkIsNullOrEmpty(Integer arg){
if(arg != null) return true;
return false;
}
public static boolean checkIsNullOrEmpty(String arg){
if(!arg.trim().equals("") || !arg.trim().equals(" ") || arg.trim() != null) return true;
return false;
}
If anyone guide me or suggest me that is there any better option available ??
create a function like this:
public static bool AllNull(object... something)
{
for(var v :something)
if(v!=null){
if(v instanceof Integer)
// do integer validation
}else
//Err msg
}
Then you could call it like this:
if (AllNull(obj1, obj2, obj3, obj4, obj5, obj6))
{
// ...
}
if you want to be specific, separate strings and integers and make separate function like this one for each type you need
Edit
as i understod from your comment, u don't know varargs
varargs are useful for any method that needs to deal with an
indeterminate number of objects. One good example is String.format.
if you can edit command, you can mark each field that you want to check null with #NotNull, then use java reflect api to get all fields marked with #NotNull, and check whether some fields null or not
I think best solution for your problem is using Java Reflect.
Here is sample code to validate all field of an instance by Java Reflect.
Example I have one instance(pojo) of object PojoObj.
PojoObj pojo = new PojoObj("one1", 2, null, 4, "five", "Six");
Validate all fields by Java Reflect.
Class<PojoObj> aClass = PojoObj.class;
Field[] fields = aClass.getDeclaredFields();
for(Field field : fields) {
Object value = field.get(pojo);
Object type = field.getType();
if(value == null) {
System.out.println(field.getName() + " is null");
} else {
System.out.println(field.getName() + " is instanceof " + type + " and value = " + value);
}
}
Output:
fieldOne is instanceof class java.lang.String and value = one1
fieldTwo is instanceof long and value = 2
fieldThree is null
fieldFour is instanceof int and value = 4
fieldFive is instanceof class java.lang.String and value = five
fieldSix is instanceof class java.lang.String and value = Six

Can't set text on label or text class because of NullPointerException

public void setBtnAction(ActionEvent event) {
String leagueNameString = nameFld.getText();
if ((leagueNameString == null) || (leagueNameString == "")) {
nameFld.setPromptText("Enter value league name");
} else {
CoreAppFXMLController cp = new CoreAppFXMLController();
cp.nameOfTheLeague.setText(leagueNameString);
}
}
}
I tried with both, text and label, but none of them works.
nameOfTheLeague is protected in CoreAppFXMLController class. It returns me NullPointerException. id's are ok in fxml.
The way you create CoreAppFXMLController, you just invoke the constructor. Nothing else will be done. That means that no nodes are created, since no fxml file is loaded and of course cp.nameOfTheLeague is never assigned.
You have to use a FXMLLoader to create Nodes and controller from a fxml file and make the assignments for the Nodes with ids.
If you don't know how to use a FXMLLoader to get the controller, it's demonstrated in this post: https://stackoverflow.com/a/24716026/2991525
Also, if you compare Strings use string1.equals(string2), not string1 == string2.

Validating user input in JTextFields (Java)

I am trying to validate user input into text boxes. I am checking whether the text box is populated or not and if it's not I need to alert the user to which text box isn't populated. My problem is that I need a way of returning which text box / variable is empty. I am aware I will need to pass 2 values in, one being the content of the text box and the other, an identifier of the text box.
Currently I have this (found on StackOverflow) which checks if each variable in the array is populated.
public boolean areAllNotEmpty(String... text){
for(String s : text) {
if(s == null || "".equals(s)) {
return false;
}
}
return true;
}
I would like it to also return something like this (commented):
public boolean areAllNotEmpty(String... text){
for(String s : text) {
if(s == null || "".equals(s)) {
// return textbox name / value OR show alert box with "Forename missing" etc
return false;
}
}
return true;
}
I implemented this method before on a C# project but it requires passing in one text box at a time with multiple method calls which I'm guessing isn't great.
public static bool IsFieldNull(TextBox currentText, string type)
{
bool allOk = false;
if (currentText.Text == "")
{
MessageBox.Show("Error - '" + type + "' field cannot be left blank, please enter some data in this field");
currentText.Focus();
return allOk;
}
else
{
allOk = true;
return allOk;
}
This is how it is called in C#.
Validation.IsFieldNull(txtBoxFixtureDate, "Fixture Date") && Validation.IsFieldNull(txtBoxTime, "Time")
If any of that doesn't make sense, let me know.
Thanks for any help.
You could pass the components to the method and return ones that are empty like this:
public List<JTextField> getEmptyFields(JTextField... textFields) {
List<JTextField> emptyFields = new ArrayList<JTextField>();
for (JTextField field : textFields) {
if (field.getText().isEmpty()) {
emptyFields.add(field);
}
}
return emptyFields;
}
Then you can just check the size() of the returned list to determine if there was an empty field and deal with them accordingly.
It's not pretty useful to validate when a submit button is pressed, it's better to validate when the error is happening. You may consider using InputVerifier . Then you know when it's in valid state or not. Apart from that if you are using java7 or above you could take a look to JLayer to decorate components which are not in valid state. See here for more examples Decorate components with JLayer.

Set remove() function does not work

while working with my application I've encountered a problem while trying to remove object from the java collection ( Set pulled from database with EclipseLink ).
The object which I want to remove in an entity class which has overriden equals method.
I've even checked whether any of the objects in the collection is eqauls to the one I want to remove with the following code:
for(AlbumEntity entity : deleteGroup.getAlbums()){
System.out.println("VAL: " + deleteAlbum.equals(entity));
}
In this case, one of the values returned is true. However, if I do:
boolean result = deleteGroup.getAlbums().remove(deleteAlbum);
the value of result is false and the size of collection stays the same.
Thanks for your help in advance
edit:
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
if (!(object instanceof AlbumEntity)) {
return false;
}
AlbumEntity other = (AlbumEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
A few possibilities:
1) There is a problem with the implementation of id's equals or hashCode methods. In this case, you could have id1.equals(id2) but id1.hashCode() != id2.hashCode(). This would cause inconsistency between equals and hashCode() for the album objects and could cause the symptoms you're seeing.
2) The id for one or more albums changes at some point after the for loop that checks deleteAlbum.equals(entity) for each album in the Set. If an id changes for an album, the remove() method may not be able to find it. An id could change from null to some non null number if got saved to the database - EclipseLink might do this for you without you explicitly asking it to.
3) Because of EclipseLink's meddling, deleteGroup might not actually be a HashSet when you run your code. The docs for EclipseLink suggest it will give you an "indirection object" instead of the java.util.Set (or java.util.HashSet I presume) declared in your class, depending on how it is configured. In that case, the contains and remove methods might not do what you expect them to.
See Overriding equals and hashCode in Java for more details on these and other possible problems involving equals and hashCode, which can cause bizarre behavior with Sets.
Okay let's try a bit of testing:
1:
Iterator<AlbumEntity> it = deleteGroup.getAlbums().iterator();
while(it.hasNext()){
AlbumEntity entity = it.next();
Assert.assertTrue(deleteGroup.getAlbums().contains(entity))
}
Does this test run successfully?

java-how to check a list of textField with a loop validation function

i want to check a list of textfield with a validation loop function
if anyone can explain me how to do this thks ;)
i do this :
public void validation()
{
List<String> list = new ArrayList<>();
list.add("LastNameTextField");
list.add("nameTextField");
list.add("ageTextField");
list.add("AdressTextField");
list.add("PhoneTextField1");
for(String check :list )
{
if(validator((check.toString()).toString()))
/*here i just want to get the field name and this value */
JOptionPane.showMessageDialog(null, check+ " Empty value");
}
}
public static boolean validator(String TextFieldTextToCheck)
{
if ((TextFieldTextToCheck== null) || (TextFieldTextToCheck.length() == 0)) {
return true ;
}
else return false;
}
i dont find the way to get the field value if anyone can help
thank you for your time
For the record, I don't have allot of Java experience. If I understand correctly, you are trying to validate the contents of several TextFields in a GUI. And the validation only makes certain that the textfield is empty. I would recommend that instead of using a collection of the textField names, you simply use a collection of references to the textfields you wish to validate.
So your ArrayList is populated with textfield references instead:
ArrayList<TextField> textFields = new ArrayList<TextField>();
textFields.add(textbox1);
textFields.add(textbox2);
textFields.add(textbox3);
textFields.add(textbox4);
You iterate through the ArrayList like before. I used a System.Out call for my own testing.:
for(TextField textField : textFields) {
if(validateTextField(textField)) {
//JOptionPane.showMessageDialog(null, textField.getText() + " Empty value");
System.out.println(textField.getName() + " has an Empty value");
}
}
The validate function now looks like this. I added a test for a NULL reference, but you could leave that out.:
public static boolean validateTextField(TextField textField) {
if(textField == null) throw new NullPointerException("The validate function received a null textfield reference. Check your loop.");
return textField.getText().length() == 0;
}
Your if condition is incorrect.
if(validator((check.toString()).toString()))
It should be corrected as:
if(YourClass.validator(check))
Explanation:
check is already String. There is not need to call toString() on it.
validator method is a static method so call it in static way as YourClass.validator where YourClass is your class name.
validator method return boolean and if expects boolean so no need to get a String again.

Categories