Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Beans in composite #526

Open
F43nd1r opened this issue Dec 10, 2019 · 2 comments
Open

Using Beans in composite #526

F43nd1r opened this issue Dec 10, 2019 · 2 comments

Comments

@F43nd1r
Copy link

F43nd1r commented Dec 10, 2019

I have a class like this

@SpringComponent
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CardView extends Div {

    @Autowired
    public CardView(...some services...) {
        ...
    }
}

which I would like to use in a composite:

public class SpringCompositeDemo extends Composite<CardView> {

This is currently not possible. My workaround is to extend Composite:

@SpringComponent
public abstract class SpringComposite<T extends Component> extends Composite<T> {
    private ApplicationContext applicationContext;

    @SuppressWarnings("unchecked")
    @Override
    protected T initContent() {
        Class<? extends Component> contentType = findContentType((Class<? extends Composite<?>>) getClass());
        if (AnnotationUtils.findAnnotation(contentType, org.springframework.stereotype.Component.class) != null)
            if (applicationContext != null) {
                return (T) applicationContext.getBean(contentType);
            } else {
                throw new IllegalStateException("Cannot access Composite content before bean initialization");
            }
        return (T) ReflectTools.createInstance(contentType);
    }

    @Autowired
    public final void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /*
     * copied from Composite#findContentType(Class)
     */
    private static Class<? extends Component> findContentType(
            Class<? extends Composite<?>> compositeClass) {
        Type type = GenericTypeReflector.getTypeParameter(
                compositeClass.getGenericSuperclass(),
                Composite.class.getTypeParameters()[0]);
        if (type instanceof Class || type instanceof ParameterizedType) {
            return GenericTypeReflector.erase(type).asSubclass(Component.class);
        }
        throw new IllegalStateException(getExceptionMessage(type));
    }

    /*
     * copied from Composite#getExceptionMessage(Type)
     */
    private static String getExceptionMessage(Type type) {
        if (type == null) {
            return "Composite is used as raw type: either add type information or override initContent().";
        }

        if (type instanceof TypeVariable) {
            return String.format(
                    "Could not determine the composite content type for TypeVariable '%s'. "
                            + "Either specify exact type or override initContent().",
                    type.getTypeName());
        }
        return String.format(
                "Could not determine the composite content type for %s. Override initContent().",
                type.getTypeName());
    }
}

It would be nice to have this work out of the box.

@Legioth
Copy link
Member

Legioth commented Dec 11, 2019

I see two ways of solving this.

One would be to include something like your SpringComposite in the Spring integration. The drawbacks here are that you'd need to do something special when using Spring and that the same implementation would have to be separately replicated for CDI as well.

The other alternative would be to make the core Composite class use Instantiator instead of ReflectTools for creating the instance. This would mean that it would automatically work for both Spring and CDI users and that you wouldn't even have to inject the composite instance. The drawbacks would be that Composite would then only be possible to instantiate when VaadinService.getCurrent() is defined and that there's a possibility of surprises for existing applications if old composites would suddenly start behaving as Spring/CDI beans.

@F43nd1r
Copy link
Author

F43nd1r commented Dec 13, 2019

I would personally prefer the second option, but any built-in solution would be appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants