Vaadin binding objects - vaadin

I am trying to bind a textfield to an object. I've done some research and I have found this answer.
public class Person {
String name;
String surname;
Address address;
// assume getters and setters
}
public class Address {
String street;
// assume getter and setters
}
Then, you could bind the street address like this:
Binder<Person> binder = new Binder<>();
TextField streetAddressField = new TextField();
// bind using lambda expressions
binder.bind(streetAddressField,
person -> person.getAddress().getStreet(),
(person, street) -> person.getAddress().setStreet(street));
What value do I instantiate street as (in the last line of code)?
The above was the example I found. My code is as follows - I have a contact class:
#Entity
public class Contact {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String phoneNumber;
#ManyToOne (cascade = {CascadeType.ALL})
#JoinColumn(name="phoneType_typeId")
private PhoneType phoneType;
public Contact(){
}
public Contact(String firstName, String lastName, String phoneNumber, PhoneType type) {
this.firstName = firstName;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.phoneType = type;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public PhoneType getPhoneType() {
return phoneType;
}
public void setPhoneType(PhoneType phoneType) {
this.phoneType = phoneType;
}
#Override
public String toString() {
return String.format("Contact[firstName='%s', lastName='%s', phoneNumber='%s', phoneType = '%s']",
firstName, lastName, phoneNumber, phoneType);
}
}
Then I have a phoneType class:
#Entity
#Table(name="phoneType")
public class PhoneType {
#Id
#GeneratedValue
#Column(name = "typeId")
private Long id;
private String type;
public PhoneType(String type){
this.type = type;
}
public PhoneType(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
Then in a Contact Editor I am trying to bind the phoneType to a textfield:
#SpringComponent
#UIScope
public class ContactEditor extends VerticalLayout {
private final ContactRepository repository;
private Contact contact;
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
TextField phoneNumber = new TextField("Phone number");
TextField phoneType = new TextField( "Phone type");
Button save = new Button("Save", VaadinIcons.CHECK);
Button cancel = new Button("Cancel");
Button delete = new Button("Delete", VaadinIcons.TRASH);
CssLayout actions = new CssLayout(save, cancel, delete);
Binder<Contact> binder = new Binder<>(Contact.class);
#Autowired
public ContactEditor(ContactRepository repository, Contact contact) {
this.repository = repository;
this.contact = contact;
String type = contact.getPhoneType().getType();
addComponents(firstName, lastName, phoneNumber, phoneType, actions);
// bind using naming convention
**binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type));**
binder.bindInstanceFields(this);
// Configure and style components
setSpacing(true);
actions.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
save.setStyleName(ValoTheme.BUTTON_PRIMARY);
save.setClickShortcut(ShortcutAction.KeyCode.ENTER);
// wire action buttons to save, delete and reset
save.addClickListener(e -> repository.save(contact));
delete.addClickListener(e -> repository.delete(contact));
cancel.addClickListener(e -> editContact(contact));
setVisible(false);
}
public interface ChangeHandler {
void onChange();
}
public final void editContact(Contact c) {
if (c == null) {
setVisible(false);
return;
}
final boolean persisted = c.getId() != null;
if (persisted) {
// Find fresh entity for editing
contact = repository.findById(c.getId()).get();
}
else {
contact = c;
}
cancel.setVisible(persisted);
// Bind customer properties to similarly named fields
// Could also use annotation or "manual binding" or programmatically
// moving values from fields to entities before saving
binder.setBean(contact);
setVisible(true);
// A hack to ensure the whole form is visible
save.focus();
// Select all text in firstName field automatically
firstName.selectAll();
}
public void setChangeHandler(ChangeHandler h) {
// ChangeHandler is notified when either save or delete
// is clicked
save.addClickListener(e -> h.onChange());
delete.addClickListener(e -> h.onChange());
}
}
The line enclosed in ** in Contact Editor (i.e. binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type))) is giving me an error - "no instance of type variable FIELDVALUE exist so that string conforms to ValueProvider .

The line
binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type));
does not compile because the method arguments do not match to any of the bind methods, and there is an illegal Java expression in the 3rd argument. According to your question, you have simply forgotten to use lambdas. Try:
binder.bind(phoneType, c -> c.getPhoneType().getType(), (c, t) -> c.getPhoneType().setType(t));
Have a look at the method signature:
public <FIELDVALUE> Binder.Binding<BEAN,FIELDVALUE> bind(HasValue<FIELDVALUE> field,
ValueProvider<BEAN,FIELDVALUE> getter,
Setter<BEAN,FIELDVALUE> setter)
It expects ValueProvider and Setter as 2nd and 3rd argument. These interfaces have only one method to be implemented, therefore you can use lambdas to pass them to bind.

I don't know if this is what you'r asking, but what I see as missing is that you haven't binded your binder to any bean.
You have created the binder, and you've told your textfield which property is binded to, but now you need to tell the binder which is his bean.
Something like:
Person yourPerson = new Person(); //or get person from database somehow
yourPerson.setAddress(new Address());
yourPerson.getAddress().setStreet("Road cool code, 404");
binder.setBean(yourPerson);
This should do the trick... if not, please explain better what you need. ;)

Related

SpringDoc swagger documentation generation exception in nested complextype

We have a Person class. Person class has a property with type PersonDetail. And PersonDetail has a property with type Mail class.
When we start the application and navigate to swagger ui html page, Mail class is not generated in components section of openapi definition and we get "Could not resolve reference: Could not resolve pointer: /components/schemas/Mail does not exist in document" error on page. As we checked if there is a complex type in the third level that time springdoc can not resolve that type.
Person and PersonDetail works fine but Mail fails.
Person->PersonDetail->Mail
public class Person {
private String name;
private PersonDetail personDetail;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PersonDetail getPersonDetail() {
return personDetail;
}
public void setPersonDetail(PersonDetail personDetail) {
this.personDetail = personDetail;
}
}
public class PersonDetail {
private String surname;
private List<Mail> mails;
public List<Mail> getMails() {
return mails;
}
public void setMails(List<Mail> mails) {
this.mails = mails;
}
}
public class Mail {
private String mailAddress;
public String getMailAddress() {
return mailAddress;
}
public void setMailAddress(String mailAddress) {
this.mailAddress = mailAddress;
}
}
#get(path = "/getPersonTest")
#operation(description = "Testttt")
#ApiResponses(value = { #ApiResponse(responseCode = "200", description = "successful operation",
content = #content(schema = #Schema(implementation = Person.class)))})
public ResponseEntity getPerson(#RequestParam String name){
Person person = new Person();
return ResponseEntity.status(HttpStatus.OK).body(person);
}
There is no issue.
It seems that you are not using the right configuration.
We already answered you here: https://github.com/springdoc/springdoc-openapi/issues/679

Join table issue in Spring Data JPA

I am trying to create a view with datas which combines two tables. I successfully implemented the join and datas are displaying properly by using spring data JPA join. Here my issue is that, when I am calling findAll() method from only one table, which returns all the data including joined table also,
I joined table Users model class like:
#Entity
#Table(name = "users")
public class Users implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "username")
public String username;
#Column(name = "password")
public String password;
#Column(name = "privid")
public Integer privid;
#OneToMany(cascade = CascadeType.ALL,mappedBy="pid")
public Set<Privillages> priviJoin;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getPrivid() {
return privid;
}
public void setPrivid(Integer privid) {
this.privid = privid;
}
public Set<Privillages> getPriviJoin() {
return priviJoin;
}
public void setPriviJoin(Set<Privillages> priviJoin) {
this.priviJoin = priviJoin;
}
public Users() {
}
}
And my second model Privillages like,
#Entity
#Table(name = "Privillages")
public class Privillages implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer Id;
#Column(name = "pname")
public String pname;
#ManyToOne(optional = false)
#JoinColumn(name = "pid", referencedColumnName = "privid")
public Users pid;
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Users getPid() {
return pid;
}
public void setPid(Users pid) {
this.pid = pid;
}
public Privillages(){
}
}
And repository containing,
#Query("select u from Users u JOIN FETCH u.priviJoin p")
Set<Users> findByUsername();
These are all my codes, here i added. The thing is that, join is properly working with expected resultset. But when I call findAll() method , the it returns all the structure including both joined table.
I called my findAll function like,
#RequestMapping("/check")
public List<Users> check() {
return (List<Users>) userRepo.findAll();
}
But result is like I previously mentioned.Here I added its screenshot,
In this figure we can see that it returns the both table values instead of users table data.
Why is it happening like this?
You defined your domain type Users to contain a reference so it gets loaded as specified.
If you want something similar to a Users object but without the reference, you have two options:
Change the Users type to not contain a reference.
Use a different type, similar to Users but without the reference. There are multiple ways to do that, but probably the simplest and most helpful in the current situation is to use a projection. See https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections

Neo4j remove existing relationships itself during adding new relationships

I have a code responsible for creating new relationship between two nodes.
At first It get a two nodes by property (pk), check if such relationship between those nodes already exists and if It doesn't not, create one.
public void createNeo4jGraphLink(#Nonnull final String childPk, #Nonnull final String parentPk) {
final UUID measureId = measureService.startMeasure(MeasureService.MeasureEvent.NEO_PERSIST);
Node child = neoRepository.findOneByPk(childPk);
Node parent = neoRepository.findOneByPk(parentPk);
checkIfLinkingAllowed(child, parent);
if (child.getPartOf() == null || !child.getPartOf().contains(parent)) {
if (child.getPartOf() == null) {
child.setPartOf(new HashSet<>());
}
child.getPartOf().add(parent);
neoRepository.save(child);
}
measureService.fixMeasure(MeasureService.MeasureEvent.NEO_PERSIST, measureId);
}
I can see that number of relationships rises in db, but one moment it sharply decrease and so on.. What reason can lead to this behavior? I've tried to use #Transactional annotation, experimented with propagation and isolation of transaction and tried without transactions at all, but it all does not work. Btw I use Spring Data Neo4j repositories. Spring Boot 1.4.4.RELEASE.
Child and parent entity' type is "Node" which is defined as a follows
#NodeEntity(label = "node")
public class Node {
private String pk = UUID.randomUUID().toString();
#JsonIgnore
private Long id;
private String name;
private Set<Node> partOf;
private String type;
public Node() {
}
#Property(name = "pk")
public String getPk() {
return pk;
}
public void setPk(String pk) {
this.pk = pk;
}
#GraphId(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Property(name = "type")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Property(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Relationship(type = "PART_OF", direction = Relationship.OUTGOING)
public Set<Node> getPartOf() {
return partOf;
}
public void setPartOf(Set<Node> partOf) {
this.partOf = partOf;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
if (!pk.equals(node.pk)) return false;
return true;
}
#Override
public int hashCode() {
return pk.hashCode();
}
}
I perform adding the relationship 1800 times, but as result have 62 relationships. Code does not throw any errors. While processing those 1800 requests, I can see in database there is any number of relationships (less then 1800), but as result only 62.
Thank you for any information

Vaadin excel export with converter values

I'm trying to export an Excel corresponding to a FilterTable using Vaadin TableExport. That Filtertable has some columns storing Dates and other class type elements, so I'm using setConverter function to print them as specific Strings:
filerTable.setConverter("dateColumn", dateConverter);
filerTable.setConverter("myClassColumn", myClassConverter);
dateConverter and myClassConverter are instances of some classes to print that column values as Strings.
The problem comes when I want to export the table as an Excel: That setConverter conversions are not being applied to the output file. For example, date cells are being exported as string ('42741,0080787037' instead of '06/01/17 0:11'). The code section to export the Excel file is:
ExcelExport exp = new ExcelExport(new CustomTableHolder(filerTable), "excel.xls");
exp.setRowHeaders(true);
exp.export();
Is there any way to export the table exactly as shown, having applied setConverter function?
Looking at the add-on sources, it seems that this feature is supported but 2 things have to happen in order for it to work:
you have to use a PropertyFormatTable (nothing fancy, just a wrapper over table for this custom purpose)
set the setUseTableFormatPropertyValue(true) on the ExcelExport
Code:
public class ExcelExportTableComponent extends VerticalLayout {
public ExcelExportTableComponent() {
// basic table configuration
Table table = new PropertyFormatTable();
BeanItemContainer<Person> itemContainer = new BeanItemContainer<>(Person.class);
table.setContainerDataSource(itemContainer);
table.setConverter("age", new AgeConverter());
// add some dummy data to the table
Random random = new Random();
for (int i = 0; i < 10; i++) {
itemContainer.addItem(new Person("Name " + i, "Surname " + i, random.nextInt(99) + 1));
}
// add components to the layout
addComponent(table);
addComponent(new Button("Export to excel", event -> {
ExcelExport excelExport = new ExcelExport(table);
excelExport.setUseTableFormatPropertyValue(true);
excelExport.excludeCollapsedColumns();
excelExport.setReportTitle("Demo Report");
excelExport.export();
}));
}
// basic bean for data binding
public static class Person {
private String name;
private String surname;
private int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// custom converter
private static class AgeConverter implements Converter<String, Integer> {
#Override
public Integer convertToModel(String value, Class<? extends Integer> targetType, Locale locale) throws ConversionException {
return Integer.valueOf(value.substring(0, value.indexOf(" years")));
}
#Override
public String convertToPresentation(Integer value, Class<? extends String> targetType, Locale locale) throws ConversionException {
return String.valueOf(value) + " years";
}
#Override
public Class<Integer> getModelType() {
return Integer.class;
}
#Override
public Class<String> getPresentationType() {
return String.class;
}
}
}
Output:

GORM is not saving my hasMany entity

So I am asking a lot about GORM lately because it's the first time I am using it, and each time I have some issues with relations between objects and saving them.
So this is one class:
class TesterUser {
#Id
private String id
private String userId
static belongsTo = Dashboard
static constraints = {
userId nullable: true
}
static mapping = {
id column: 'id', generator: 'assigned'
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
And this is the other class:
class TestingClass {
#Id
private String id
private Date created
private Date modified
private String title
private ClassName className
static hasMany = [testUsers : TesterUser, sheets : Sheet]
static belongsTo = ClassName
static constraints = {
modified nullable: true
title nullable: true
className nullable: true
}
static mapping = {
sheets column:'testingClassId',joinTable: false
testUsers column:'testingClassId',joinTable: false
id column: 'id', generator: 'assigned'
title column: "title", length: 90000
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public DavUser getClassName() {
return className;
}
public void setClassName(ClassName className) {
this.className = className;
}
public Date getDeleted() {
return deleted;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
I already saved the objects in the DB, but now I want to set the relations between them and when I call and save them it's not working:
TesterUser testU = TesterUser.findById(uId)
TestingClass testC = TestingClass.findById(cId)
if(testU != null && testC != null){
amountOfRelations++
testC.addToDashboardUsers(testU)
if(!dtestC.save(flush:true, failOnError: true)){
amountOfUnsaved++
}
else{
amountOfsaved++
}
For some reason, I get no error. Not only that, I can see the queries are going to my db, but nothing happens. There is no update and no error.
I have no idea why it's not working.
Any idea?
Eventually I was not able to save my entities.
My 'solution' was to save the entity in the first place using addTo method.
I still don't know why it didn't work or what I needed to do in order to make my entity to be saved, but still I got a workaround.

Resources