Cannot load/save properties of the ViewModel's property - java

I have problem accessing the property of an object inside my ViewModel. I got unreached destination error. Any pointers please? Thanks.
Error Message:
Target Unreachable, 'toto' returned null
Basically, I will get the error when I fill in the textbox and click somewhere in the window. When I use other ViewModel's property (which is a String), it works as I expected.
Setup:
I use JBoss Studio. The app is running on JBoss AS 7. Basically I follow this guide http://books.zkoss.org/wiki/ZK_Installation_Guide/Quick_Start/Create_and_Run_Your_First_ZK_Application_with_Eclipse_and_Maven to create my project.
Zul file:
<window apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('com.maylab.fault.TicketsViewModel')"
title="Trouble Ticket" width="600px" border="normal">
<hbox style="margin-top:20px">
<textbox value="#save(vm.toto.name)"></textbox>
<label value="#load(vm.toto.name)"></label>
</hbox>
</window>
ViewModel:
package com.maylab.fault;
import org.zkoss.bind.annotation.*;
import com.maylab.fault.Person;
public class TicketsViewModel {
private String ticket;
private String test;
private Person toto;
public Person getToto() {
return toto;
}
public void setToto(Person toto) {
this.toto = toto;
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
}
Person class:
package com.maylab.fault;
public class Person {
private String name;
public Person(){
}
public Person(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

If you will check your viewmodel, you have wrote this code private Person toto; and with get/set method now as you know toto=null so to resolve this issue you have to change your code like this
private Person toto = new Person();
this will resolve your issue.

Related

How to load a combobox with vaadin fusion

Hi I'm using the vaadin starter in order to learn more about vaadin.
I just started a new project (Java+Typescript)
I am having issues to solve an issue.
I have a Users and Rol Entity, being Rol an attribute of User, the thing is when I am setting the views created with vaading start I am trying to set up a combo box to load Roles to be used to create a new user but nothing work so far.
In the tutorial in vaading web page they solve this in a way that is way different to the arch and files created by the vaadin start so I thought that maybe would be another way to do it.
My entities
User
package com.example.application.data.entity;
import com.vaadin.fusion.Nonnull;
import com.example.application.data.AbstractEntity;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
#Entity
public class Users extends AbstractEntity {
#ManyToOne
#Nonnull
private Rol rol;
public Rol getRol() {
return rol;
}
public void setRol(Rol rol) {
this.rol = rol;
}
}
Rol
package com.example.application.data.entity;
import com.vaadin.fusion.Nonnull;
import com.example.application.data.AbstractEntity;
import javax.persistence.Entity;
#Entity
public class Rol extends AbstractEntity{
#Nonnull
private String name;
#Nonnull
private String description;
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;
}
}
What should I do to load this with all roles in order to select one in my users-view.ts
<vaadin-combo-box label="Rol" id="rol" ${field(this.binder.model.rol)} item-label-path="name"></vaadin-combo-box>
Right now I'getting this
How the combobox shows
Thanks in advance guys.
My Solution was:
added tis lines to my typescrypt class
#state()
private roles: Rol[] = [];
#state from 'lit/decorators.js'
then in the connectedCallback function added this line
this.roles = await RolesEndpoint.listAll();
listAll() is a method that I created on my endpint class.
like this:
#Nonnull
public List<#Nonnull Rol> listAll() {
return service.listAll();
}
and in my service class
public List<Rol> listAll() {
return repository.findAll();
}
Now you can call the data in your combobox element
<vaadin-combo-box .items=${this.roles} label="Rol" id="rol" ${field(this.binder.model.rol)} item-label-path="name" item-value-path="id"></vaadin-combo-box>
I hope this can be helpful.

Lombok's builder with mandatory parameters

If I add #Builder to a class. The builder method is created.
Person.builder().name("john").surname("Smith").build();
I have a requirement where a particular field is mandatory. In this case, the name field is mandatory. Ideally, I would like to declare it like so.
Person.builder("john").surname("Smith").build();
When googling i found many alternatives like overriding the builder implementation as below:
#Builder
public class Person {
private String name;
private String surname;
public static PersonBuilder builder(String name) {
return new PersonBuilder().name(name);
}
}
And then use it like below:
Person p = Person.builder("Name").surname("Surname").build();
The problem with above approach is that it still provides the name() and PersonBuilder() method like below, which i don't want:
Person p = Person.builder("Name").surname("Surname").name("").build();
Person p = new Person.PersonBuilder().build;
Another approach is to add #lombok.nonnull check at name which will force to provide value for name while creating object. but it is a runtime check. it will not force me to provide value for name while creating object.
Is there any additional technique which lombok provides to achieve below:
Person p = Person.builder("Name").surname("Surname").build();
Note: The builder() and name() should not be exposed. The only way to create Person object should be either above or below:
Person p = Person.builder("Name").build();
You can't really do it with lombok, see the explanation from the library authors. But is it that complicated to roll this builder on your own?
public static class PersonBuilder {
private final String name;
private String surname;
PersonBuilder(String name) {
this.name = name;
}
public PersonBuilder surname(String surname) {
this.surname = surname;
return this;
}
public Person build() {
return new Person(name, surname);
}
}
with the same method that you already have:
public static PersonBuilder builder(String name) {
return new PersonBuilder(name);
}
Try to make the builder private.
Did you check this comment Required arguments with a Lombok #Builder
I am pretty sure you will find out once read the thread one more time.
P.S. If you have a class with only two field better use directly a constructor.
Best Practice:
import lombok.Builder;
import lombok.NonNull;
#Builder(builderMethodName = "privateBuilder")
public class Person {
#NonNull
private String name;
private String surname;
public static class PersonNameBuilder {
public PersonBuilder name(String name) {
return Person.privateBuilder().name(name);
}
}
private static class PersonExtraBuilder extends PersonBuilder{
#Deprecated
#Override
public PersonBuilder name(String name) {
return this;
}
}
public static PersonNameBuilder builder(String name) {
return new PersonNameBuilder();
}
private static PersonExtraBuilder privateBuilder(){
return new PersonExtraBuilder();
}
}
Usage:
PersonNameBuilder nameBuilder = Person.builder();
PersonBuilder builder = nameBuilder.name("John");
Person p1 = builder.surname("Smith").build();
// Or
Person p2 = Person.builder().name("John").surname("Smith").build();
// The last `.name("")` will not work, and it will be marked as Deprecated by IDE.
Person p3 = Person.builder().name("John").surname("Smith").name("").build();

Vaadin BeanFieldGroup - "Property is not cascaded" when binding nested property

I've been searching for hours on here and on the Vaadin forums, but I seem to have a unique problem here.
I simplified my problem a lot to be able to illustrate it easily.
So I have a Bean class:
public class Bean {
private String name;
private NestedBean nestedBean;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public NestedBean getNestedBean() {
return nestedBean;
}
public void setNestedBean(NestedBean nestedBean) {
this.nestedBean = nestedBean;
}
Bean() {
this.name = "Bean";
this.nestedBean = new NestedBean();
}
}
And its nested field, class NestedBean:
public class NestedBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
NestedBean() {
this.name = "NestedBean";
}
}
So now I want to bind an instance of Bean to two TextFields, with the help of a BeanFieldGroup:
Bean bean = new Bean();
BeanFieldGroup<Bean> binder = new BeanFieldGroup<>(Bean.class);
binder.setItemDataSource(bean);
addComponent(binder.buildAndBind("Name", "name"));
addComponent(binder.buildAndBind("Nested name", "nestedBean.name"));
This, however, throws this exception:
java.lang.IllegalArgumentException: Property com.reygok.vaadin.main.Bean.nestedBean is not cascaded
Caused by: org.apache.bval.jsr.UnknownPropertyException: Property com.reygok.vaadin.main.Bean.nestedBean is not cascaded
I tried different solutions, like:
Creating the TextFields first and then using
binder.bind(textField, "nestedBean.name");
Doing this first:
binder.getItemDataSource().addNestedProperty("nestedBean.name");
But nothing changed the Exception. So does someone know what causes this?
Thanks a lot in advance!
I found it, so if others have the same problem:
The solution is to add the #Valid annotation to the fields that have nested fields inside of them.
So in my example:
public class Bean {
private String name;
#Valid
private NestedBean nestedBean;
...
I recommand you to bind member before setting bean data source
BeanFieldGroup<Bean> binder = new BeanFieldGroup<>(Bean.class);
// first
addComponent(binder.buildAndBind("Name", "name"));
addComponent(binder.buildAndBind("Nested name", "nestedBean.name"));
// then
binder.setItemDataSource(bean);

How to edit a content assist behavior in eclipse

Is there a way to edit the content behavior or is there a plugin that does the following ... ?
I have a JSF project
the content assistant completes phrases only for attributes that has getters/setters methods
#ManagedBean(name = "myBean")
#ViewScoped
public class ViewScopedBean {
String name;
String age;
public ViewScopedBean() {
}
public String method() {
return null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
using ctrl+space in <h:commandButton value="action listener" actionListener="#{myBean.<ctrl+space>}" /> shows only methods and name attribute, is there away to make it also show the age attribute ?

Audit fields of a class using a class level annotation (aspectj)

I'm writing a simple auditing framework with aspectj, which allows me to audit the fields of a class which are annotated with an #Audit annotation.
As value the #Audit annotation expects an array of field names to be watched
Example Usage:
#Audit({"name","phoneNumber"})
class User {
private String name;
private String phoneNumber;
public getName(){
return name;
};
public setName(String name){
this.name=name;
}
}
How does the Aspect look that watches the assignment of fields that are annotated like in the above example?
Here the stub of my first try:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface Audit {
String[] value()
}
#Aspect
class AuditAspect {
#Pointcut("????")
public void markedFieldWasModified(){}
#AfterReturning("markedFieldWasModified()")
public void addFieldToModifiedFields(JoinPoint jp, AuditableEO eo){
eo.addModifiedField(jp.getSignature().getName());
}
// inter Type declarations
public interface IAuditableEO {
public Iterator<String> modifiedFields();
public boolean modified();
public boolean addModifiedField(String field);
};
}
according to https://eclipse.org/aspectj/doc/next/quick5.pdf
you should be able to do set(* *.*) && #target(Audit)
you then have to check the joinpoint if an auditable field is being modified.
How about not over-engineering the whole thing and directly annotating fields instead of classes? You can also skip the IAuditableEO interface IMO, I cannot see why it would be useful. Here is a simple example similar to yours, just with the aspect in code-style syntax (I prefer it to annotation-style syntax for clarity, but you can easily convert it by yourself):
Audit annotation for fields (not classes):
package de.scrum_master.app;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD})
public #interface Audit {}
User class with a sample main method:
package de.scrum_master.app;
public class User {
private int id;
#Audit private String name;
#Audit private String phoneNumber;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPhoneNumber() { return phoneNumber; }
public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; }
public static void main(String[] args) {
User user = new User();
user.setId(11);
user.setName("John Doe");
user.setPhoneNumber("+49-1111-23456789");
System.out.println("User(" + user.getId() + ", " + user.getName() + ", " + user.getPhoneNumber() + ")");
}
}
Audit aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Audit;
public aspect AuditAspect {
pointcut fieldModification() : set(#Audit * *);
after() : fieldModification() {
System.out.println(thisJoinPointStaticPart);
}
}
Sample output:
set(String de.scrum_master.app.User.name)
set(String de.scrum_master.app.User.phoneNumber)
User(11, John Doe, +49-1111-23456789)
As you can see, only the annotated fields are caught, not the ID field. This permits for fine-granular auditing on a per-field basis. Furthermore in the advide you have everything you need if you want to record anything in and audit database: field type and name, class name and so forth.

Categories

Resources