Abstract property in BeanContainer

Hello,
I have a bean, that one property is an interface without any method:

public class Security {
   
    <some common properties>

    private SecurityTail tail;

    <getters an setters>

    public SecurityTail getTail() {
        return tail;
    }
    
    public void setTail(SecurityTail tail) {
        this.tail = tail;
    }

}

[code]
public interface SecurityTail {}

[/code]I display the beans in tables with AbstractBeanContainer. I have the main table with all security types and it works fine. But I would like to display other table with specified kind of security, ie. in each table the
tail
property would be of the same (not abstact type). Is it possible?
Now when trying to add property
tail.effectiveDate
I get an exception:

java.lang.IllegalArgumentException: Bean property 'effectiveDate' not found at com.vaadin.data.util.NestedMethodProperty.initialize(NestedMethodProperty.java:146) at com.vaadin.data.util.NestedMethodProperty.<init>(NestedMethodProperty.java:106) at com.vaadin.data.util.NestedPropertyDescriptor.<init>(NestedPropertyDescriptor.java:52) at com.vaadin.data.util.AbstractBeanContainer.addNestedContainerProperty(AbstractBeanContainer.java:853) at cz.px.iis.ng.ui.view.PxTableViewRoot.init(PxTableViewRoot.java:542) at cz.pse.agata.commons.ui.view.PxTabWithTableAndMenuWithBasicOperations.init(PxTabWithTableAndMenuWithBasicOperations.java:175) at cz.px.iis.ng.ui.view.PxTableViewRoot.attach(PxTableViewRoot.java:980) at com.vaadin.ui.AbstractComponent.setParent(AbstractComponent.java:484) at com.vaadin.ui.AbstractComponentContainer.addComponent(AbstractComponentContainer.java:210) at com.vaadin.ui.TabSheet.addTab(TabSheet.java:342) at com.vaadin.ui.TabSheet.addTab(TabSheet.java:378) at com.vaadin.ui.TabSheet.addTab(TabSheet.java:359) at cz.px.iis.ng.ui.PxUI.addTab(PxUI.java:146) at cz.pse.agata.commons.CommonUI.addPxTab(CommonUI.java:368) at cz.pse.cp.ui.view.SecuritiesView.lambda$3(SecuritiesView.java:187) at cz.pse.cp.ui.view.SecuritiesView$$Lambda$9/1079210580.execute(Unknown Source) at cz.px.iis.ng.ui.menu.PxActionFactory$PxAction$1.buttonClick(PxActionFactory.java:142) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508) at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:198) at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161) at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:979) at com.vaadin.ui.Button.fireClick(Button.java:393) at com.vaadin.ui.Button$1.click(Button.java:57) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:168) at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118) at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:287) at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:180) at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:93) at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41) at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1406) at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:305) at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:611) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.NoSuchMethodException: cz.pse.agata.commons.dto.SecurityTail.areEffectiveDate() at java.lang.Class.getMethod(Class.java:1773) at com.vaadin.data.util.MethodProperty.initGetterMethod(MethodProperty.java:547) at com.vaadin.data.util.NestedMethodProperty.initialize(NestedMethodProperty.java:141) ... 55 more even thought this concrete tail has method
getEffectiveDate().

Hi, I could have a look at it if you attach an example project.

Hi Alejandro,
at last I implemented it in following way:

[code]
private static class MyNestedPropertyDescriptor implements VaadinPropertyDescriptor{

    private static final long serialVersionUID = 6525407357415432577L;

    private String name;
    private Class<?> propertyType;
    private Class<?> middleType;

    public MyNestedPropertyDescriptor(String name, Class<BT> beanType, Class<?> propType){
        this.name = name;
        MyNestedMethodProperty<?> property = new MyNestedMethodProperty<Object>(
                beanType, propType, name);
        this.middleType = propType;
        this.propertyType = property.getType();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Class<?> getPropertyType() {
        return propertyType;
    }

    @Override
    public Property<?> createProperty(BT bean) {
        return new MyNestedMethodProperty<>(bean, middleType, name);
    }
            
}

private static class MyNestedMethodProperty<T> extends AbstractProperty<T>{

    private static final long serialVersionUID = -4842009339734837059L;

    private Object instance;
    private Method firstGetter;
    private Method secondGetter;
    private Method setMethod;
    private Class<? extends T> type;

    public MyNestedMethodProperty(Object instance, Class<?> propertyType, String propertyName){
        this.instance = instance;
        initialize(instance.getClass(), propertyType, propertyName);
    }
    
    public MyNestedMethodProperty(Class<?> instanceClass, Class<?> propertyType, String propertyName){
        instance = null;
        initialize(instanceClass, propertyType, propertyName);
    }
    
    private void initialize(Class<?> beanClass, Class<?> propertyClass, String propertyName) {
        String simplePropertyNames = propertyName.split("\\.");
        try {
            firstGetter = NestedMethodProperty.initGetterMethod(simplePropertyNames[0]

, beanClass);
secondGetter = NestedMethodProperty.initGetterMethod(simplePropertyNames[1]
, propertyClass);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(“Bean property not found”, e);
}
type = (Class<? extends T>) secondGetter.getReturnType();
try {
setMethod = propertyClass.getMethod(“set” + simplePropertyNames[1]
, new Class { type });
} catch (NoSuchMethodException | SecurityException e) {
}
}

    @Override
    public T getValue() {
        Object v1;
        try {
            v1 = firstGetter.invoke(instance);
            return v1 == null ? null : (T)secondGetter.invoke(v1);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new MethodException(this, e);
        }
    }

    @Override
    public void setValue(T newValue) throws com.vaadin.data.Property.ReadOnlyException {
        try {
            Object v1 = firstGetter.invoke(instance);
            setMethod.invoke(v1, newValue);
        } catch (IllegalAccessException | IllegalArgumentException e) {
            throw new MethodException(this, e);
        } catch (InvocationTargetException e) {
            throw new MethodException(this, e.getTargetException());
        }
        fireValueChange();
    }

    @Override
    public Class<? extends T> getType() {
        return type;
    }
    
}

private static class SecurityHistoryContainer<T extends SecurityTail> extends BeanItemContainer<Security> {

    private static final long serialVersionUID = -6287052228121829118L;

    private Class<T> tailClass;

    public SecurityHistoryContainer(Class<T> tailClass) throws IllegalArgumentException {
        super(Security.class);
        this.tailClass = tailClass;
    }
    
    @Override
    public boolean addNestedContainerProperty(String propertyId) {
        if (!propertyId.startsWith("tail.")) {
            return super.addNestedContainerProperty(propertyId);
        }
        return addContainerProperty(propertyId, new MyNestedPropertyDescriptor<>(propertyId, Security.class, tailClass));
    }
    
}

[/code]It doesn’t work for nested properties in tail, but such functionality is enough for me.

Hi, thanks for sharing.

The problem is that the
SecurityTail
interface doesn’t declare any
getEffectiveDate
nor
setEffectiveDate
methods at all. Behind the scenes,
BeanItemContainer
uses Java reflextion to “discover” properties (and so does your own implementation). In this case it will try to find Java getters and setters in the
SecurityTail
interface and there are none. The properties are “discovered” at container creation time when no items have been added. Hence, even if you add items to the container and these items correspond to
Security
instances having references to concrete implementations of
SecurityTail
that in turn do contain the
effectiveDate
field, there’s no way this property could be discovered.

I would suggest to check whether the design can be improved. Particularly, I would question the need of a
SecurityTail
interface with no methods. I understand that you may have several implementations of
SecurityTail
and setting instances of them according to some business rules, but still looks like not the best design. I may be missing something, though.

Hope that helps.

Alejandro, I understand all that, but the
SecurityTail
can have any properties (even none) and there are not any in common.
Any way, because of having problems with MyBatis also, I changed the architecture by creating classes inheriting from
Security
instead of having the a tail. With this solution I can use
Mcont
and everything works as expected.

Agata