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

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);

Related

Spring Boot JPA Query Error - "No property '' found for type '' " Exception

I am currently studying an online Spring Boot course working with Spring Data JPA.
My project includes 2 entities: BDProject and BDUser which have a many to one relationship. When attempting to find projects from user id the following exception is displayed.
EXCEPTION
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectController': Unsatisfied dependency expressed through field 'bdProjectService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectService': Unsatisfied dependency expressed through field 'bdProjectRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BDProjectRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.project.bdproject.BDProjectRepository.findByUserID(java.lang.String)! No property userID found for type BDProject!
I have spent hours trying to figure out what's causing this exception, but nothing seems to be fixing it.
MY CODE:
Entities
#Entity
public class BDUser {
#Id
private String userID;
private String bdUsername;
private String bdUserEmail;
private String bdUserPassword;
public BDUser(){
}
public BDUser(String userID, String bdUsername, String bdUserEmail, String bdUserPassword) {
super();
this.userID = userID;
this.bdUsername = bdUsername;
this.bdUserEmail = bdUserEmail;
this.bdUserPassword = bdUserPassword;
}
// getters and setters...
#Entity
public class BDProject {
#Id
private String proID;
private String proName;
private String proCodeOwner;
private String proIDs;
#ManyToOne
private BDUser bdUser;
public BDProject() {
}
public BDProject(String proID, String proName, String proCodeOwner, String proIDs, String userID) {
super();
this.proID = proID;
this.proName = proName;
this.proCodeOwner = proCodeOwner;
this.proIDs = proIDs;
this.bdUser = new BDUser(userID, "", "", "");
}
// getters and setters...
Controller
#RestController
public class BDProjectController {
#Autowired
private BDProjectService bdProjectService;
#RequestMapping("/bdusers/{userID}/bdprojects")
public List<BDProject> getAllProjects(#PathVariable String proID){
return bdProjectService.getAllProjects(proID);
}
#RequestMapping("/bdusers/{userID}/bdprojects/{proID}")
public BDProject getProject(#PathVariable String proID){
return bdProjectService.getProject(proID);
}
#RequestMapping(method= RequestMethod.POST, value="/bdusers/{userID}/bdprojects")
public void addProject(#RequestBody BDProject bdProject, #PathVariable String userID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.addProject(bdProject);
}
#RequestMapping(method= RequestMethod.PUT, value="/bdusers/{userID}/bdprojects/{proID}")
public void updateProject(#RequestBody BDProject bdProject, #PathVariable String userID, #PathVariable String proID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.updateProject(bdProject);
}
#RequestMapping(method= RequestMethod.DELETE, value="/bdusers/{userID}/bdprojects/{proID}")
public void deleteProject(#PathVariable String proID){
bdProjectService.deleteProject(proID);
}
}
Service
#Service
public class BDProjectService {
#Autowired
private BDProjectRepository bdProjectRepository;
public List<BDProject> getAllProjects(String userID){
List<BDProject> bdProjects = new ArrayList<>();
bdProjectRepository.findByUserID(userID).forEach(bdProjects::add);
return bdProjects;
}
public BDProject getProject(String proID){
return bdProjectRepository.findById(proID).orElse(null);
}
public void addProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void updateProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void deleteProject(String proID){
bdProjectRepository.deleteById(proID);
}
}
Repository
public interface BDProjectRepository extends CrudRepository<BDProject, String>{
public List<BDProject> findByUserID(String userID);
}
Any and all help is much appreciated. Thanks!
In BDProject you have property
private BDUser bdUser;
and in the repository you have:
public List<BDProject> findByUserID(String userID);
Error states that in BDProject you don't have property userID which is correct since you have bdUser.
Therefore, please change
findByUserID(String userID) to findByBdUserUserID(String userID)
You have created a BDProjectRepository interface for BDProject entity.
Please modify the method in that repository:
now: public List<BDProject> findByUserID(String userID);
should be: public List<BDProject> findByProID(String proID);
If you want to get BDProject for a specific user you can retrieve it by querying the related object as
public List<BDProject> findByBdUser_UserID(String proID);
When querying by fields in referenced object you should write it like ChildObject_ChildID
public interface BDProjectRepository extends CrudRepository<BDProject, String>
{
public List<BDProject> findByBdUser_UserID(String userID);
}

Mapstruct: Clear Collection on update when using Adders

I try to map my DTO objects to my JPA entities. I have a Collection of children in my ParentEntity. They can be added addChild(). Using the Adder is supported by Mapstruct via the CollectionMappingStrategy (http://mapstruct.org/documentation/dev/reference/html/#collection-mapping-strategies).
This works fine if I create new entities, but fails to clear the children on updating before adding the new children.
The Mapstruct manual says (http://mapstruct.org/documentation/dev/reference/html/#updating-bean-instances):
Collection- or map-typed properties of the target bean to be updated will be cleared and then populated with the values from the corresponding source collection or map.
What am I missing? Is there an additional option I have to set? There is a full example with test case to reproduce the problem at https://github.com/davidfuhr/mapstruct-jpa-child-parent
Here are the classes:
public class ParentEntity {
private String name;
private List<ChildEntity> children = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ChildEntity> getChildren() {
return children;
}
public void addChild(ChildEntity child) {
children.add(child);
child.setMyParent(this);
}
public void removeChild(ChildEntity child) {
children.remove(child);
child.setMyParent(null);
}
}
public class ChildEntity {
private String name;
private ParentEntity myParent;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ParentEntity getMyParent() {
return myParent;
}
public void setMyParent(ParentEntity myParent) {
this.myParent = myParent;
}
}
public class ParentDto {
private String name;
private List<ChildDto> children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ChildDto> getChildren() {
return children;
}
public void setChildren(List<ChildDto> children) {
this.children = children;
}
}
public class ChildDto {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);
ParentEntity toEntity(ParentDto s);
ParentEntity updateEntity(ParentDto s, #MappingTarget ParentEntity e);
#Mapping(target = "myParent", ignore = true)
ChildEntity toEntity(ChildDto s);
}
The text in the documentation need to be rephrased. The problem is that especially for collections, there's no good way to handle this out of the box in MapStruct. I'm currently writing some new text for the documentation.
Consider this (when thinking what MapStruct should do for updating collections in general):
What if there's no match: should the non-matching elements be removed?
Should the non matching source elements be added?
What exactly constitutes to a match: equals? hashcode? comparator==0?
Can there be more than one match (Lists, but also depending on what is considered a match.)
How should the resulting collection be sorted?
Should a newly created object be added to a persistence context?
What about JPA child-parent relations?
About the latter one, Dali (Eclipse) also generates remove methods. So should MapStruct call these in the light of the above?
At this moment it works like this: whenever the user wants a collection update method, MapStruct generates a regular call to element mappings (in stead of an update call), because it is the only sensible thing to do. All the remainder is highly dependent on the use-case. If you need to clear the collection at before hand, use the #BeforeMapping to clear it.
Note: I just fixed an issue that handles also adders in this fashion in stead of the vague error message you get now.
If you want a nice way to handle child/parent relations and integrate them with JPA.. have a look at the examples.

How to map single JSON field to multiple JAVA field with GSON?

I'm trying to parse JSON using Retrofit and Gson, but I need to map one JSONfield
's value to multiple JAVA fields inside bean class.
Here is an example code:
class A{
#SerializedName("name");
private String name;
#SerializedName("name");
private String fullName;
}
This is the error I'm seeing: class A declares multiple JSON fields named name. Is there any way to do this?
Update: Please avoid suggesting removing one field from the bean or making changes into getter and setter. The project is huge, and the field is being used later in many other cases, so I don't want to mess with the structure. The question is pretty much clear and on the point.
No need to declare JSON for fullname use name value with fullname in setter gatter.
class A{
#SerializedName("name");
private String name;
private String fullName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFullName() {
return name;
}
public void setFullName(String fullName) {
this.name = fullName;
}
}

JavaFX bind not property member to control

Imagine I have a POJO like:
public class Person()
{
private int id;
private String name;
public int getId()
{
return this.id;
}
public String getName()
{
return this.name;
}
}
If I need to bind name member to JavaFX label using bind() method, I can't apply because I need and observable value.
I know that I can use StringProperty instead String, but I need primitive types because I use Hibernate and I don't know if Hibernate could support properties from JavaFX to map data from DB.
Which alternatives I have to bind from my pojo to a JavaFX control?
You have a couple of options here.
Firstly, it's possible to use FX Properties in JPA/Hibernate entities, though you have to be a little careful. In short, you need to make sure you use property access so that the ORM calls the get/set methods, instead of trying to set the field directly. Steven van Impe discusses this on his blog, and I also blogged on the same topic. One thing I haven't tried here is mapping collections and using ObservableLists: that might be tricky as JPA implementations use a subinterface of List.
Your other option is to make the properties "bound properties" in the Java Bean sense, and then to use a Java Bean Property Adapter:
import java.beans.PropertyChangeSupport ;
public class Person()
{
private int id;
private String name;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public int getId()
{
return this.id;
}
public void setId(int id)
{
int oldId = this.id ;
this.id = id ;
pcs.firePropertyChange("id", oldId, id);
}
public String getName()
{
return this.name;
}
public void setName(String name)
{
String oldName = this.name ;
this.name = name ;
pcs.firePropertyChange("name", oldName, name);
}
}
Then you can do
Label nameLabel = new Label();
Person person = new Person();
nameLabel.textProperty().bind(JavaBeanStringPropertyBuilder.create()
.bean(person)
.name("name") // name of property to bind to
.build());

Spring NotBlank annotation with errorCode parameter

I have the following form:
public class Form {
#NotBlank(errorCode = "my.custom.error")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My goal is to reject value with specified error code.
But unfortunately, I cannot do it.
The field rejected with my message wrapped by Form name.
Will be good to know in which way error code for the similar annotation can be specified?

Categories

Resources