Affects: 5.1.6.RELEASE


My Spring Controller method, which handles a post request, will throw the following exception when doing the data binding:

NullValueInNestedPathException: Invalid property 'parent' of bean class [AreaImpl]: Could not instantiate property type [Area] to auto-grow nested property path; nested exception is java.lang.NoSuchMethodException: Area.()

The reason seems to be that the data container object has an interface as an attribute. In the below instance (and for simplicity) it is a recursively nesting attribute, but I don't think that is the problem. Since you can't have constructors for interfaces, the reflection code fails and says it can't instantiate it. I understand that it's impossible to guess at implementations, so that is not the issue here.

I read that I can disable autoGrowNestedPaths, but that leads to a host of other problems with null objects everywhere, so that's not a solution either for me. However, I've found a workaround ! If my Entity class has two setters for the interface attribute, then the code will work without a hitch, but only if they are defined in the data container object in a specific order.

    interface Area {
        Area getParent();
        void setParent(Area parent);
    }

The following implementation will throw the above exception, whether or not setParent(AreaImpl1) exists:

    class AreaImpl1 implements Area {
        Area parent;

        @Override
        public Area getParent() {
            return parent;
        }

        @Override
        public void setParent(Area parent) {
            this.parent = parent;
        }

        public void setParent(AreaImpl1 parent) {
            this.parent = parent;
        }
    }

The following implementation will give valid data binding!

    class AreaImpl2 implements Area {
        Area parent;

        @Override
        public Area getParent() {
            return parent;
        }

        public void setParent(AreaImpl2 parent) {
            this.parent = parent;
        }

        @Override
        public void setParent(Area parent) {
            this.parent = parent;
        }
    }

I've traced the issue into AbstractNestablePropertyAccessor.getPropertyTypeDescriptor, but I don't know if the resulting behavior is expected or buggy. If it is expected behavior, then I haven't found any documentation describing it, so this may be a documentation bug as well.

I don't mind adding the extra method to my entire domain layer (though it is a weird thing to have to do, and there may be some problems when there are actually multiple classes that can implement the interface), but I do mind that the order is important: it can make any refactoring, automated or otherwise, very brittle, and the resulting exceptions are not at all relatable to the root cause of the issue.

Comment From: Yusuf010191

Nono

Comment From: snicoll

@blagae I am trying to better understand the problem here and could use a small sample that helps me replicate the problem. You can attach a zip to this issue or share the link to a separate GitHub repo. Thanks!

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: blagae

Hi @snicoll

While I must commend you for looking at this 4 year old issue, this is code from a project that I abandoned relatively soon after this, because of shifting priorities. It was also at that time already a legacy project that I had picked up again for a final time, so the codebase was always a bit of a mess.

I have no idea anymore what the issue was that I encountered beyond the information provided above; I do remember debugging into the Spring code (which I had never really done before) and pinpointing the issue, but I knew of no real alternative.

I will hereby provide you with the stripped-down implementation of the Controller and the Dao that used this data entity, However, I am unsure if it's enough and I don't think I will try and get the whole thing running again.

interface Area {
    Area getParent();
    void setParent(Area parent);
}
@Entity
public class AreaImpl implements Area {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(targetEntity = AreaImpl.class, cascade = CascadeType.ALL)
    private Area parent;

    @OneToMany(targetEntity = AreaImpl.class, cascade = CascadeType.ALL, mappedBy = "parent")
    private Set<Area> children;


    @Override
    public Long getId() {
        return id;
    }

    @Override
    public void setId(Long t) {
        id = t;
    }

    /* This method is here for data binding; it must be BEFORE the Area method or Spring will flip out */
    // ^ this is an actual comment from 2019; as stated above, move this to the bottom of the class definition for weird results.
    public void setParent(AreaImpl parent) {
        this.parent = parent;
    }

    @Override
    public void setParent(Area parent) {
        this.parent = parent;
    }

    @Override
    public Area getParent() {
        return parent;
    }
}
import org.springframework.data.repository.CrudRepository;

public interface GenericDao<E, ID extends Serializable> extends CrudRepository<E, ID> {

    E findByName(String name);
}
import org.springframework.stereotype.Repository;

@Repository
public interface AreaDao extends GenericDao<AreaImpl, Long> {}
@Controller
@RequestMapping("/areas")
@Transactional
public class AreaController {

    @Autowired
    private AreaDao areaDao;

    @RequestMapping(value = {"index", ""}, method = RequestMethod.GET)
    public String handleMyRequest(Model model) {
        registerList(model, areaDao.findAll());
        return "/areas/list";
    }

}

Comment From: snicoll

However, I am unsure if it's enough and I don't think I will try and get the whole thing running again.

It isn't I am afraid. Without a way for us to replicate the problem you've described, I am afraid this issue is no longer actionable. Thanks for the follow-up in any case!