io.devbench.uibuilder.spring.component.ControllerBeanComponentInjectionBeanFactory Maven / Gradle / Ivy
/*
*
* Copyright © 2018 Webvalto Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.devbench.uibuilder.spring.component;
import com.vaadin.flow.component.Component;
import io.devbench.uibuilder.api.controllerbean.UIComponent;
import io.devbench.uibuilder.core.controllerbean.ControllerBeanManager;
import io.devbench.uibuilder.core.utils.reflection.PropertyMetadata;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.function.Supplier;
@Service
public class ControllerBeanComponentInjectionBeanFactory implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class> beanClass = bean.getClass();
ReflectionUtils.doWithFields(beanClass, field -> {
String componentId = field.getAnnotation(UIComponent.class).value();
boolean accessible = field.isAccessible();
field.setAccessible(true);
Class> fieldType = field.getType();
if (ObjectProvider.class.isAssignableFrom(fieldType) || Provider.class.isAssignableFrom(fieldType)) {
@SuppressWarnings("unchecked")
Class extends Component> componentType = (Class extends Component>) PropertyMetadata.findGenericType(field)
.filter(Component.class::isAssignableFrom)
.orElse(null);
if (componentType != null) {
field.set(bean, new ComponentObjectProvider<>(() -> findComponentById(componentId, componentType)));
}
}
field.setAccessible(accessible);
}, field -> field.getAnnotation(UIComponent.class) != null);
return bean;
}
private Component findComponentById(@NotNull String componentId, @NotNull Class extends Component> componentClass) {
return ControllerBeanManager
.getInstance()
.getAllCachedComponentInjectionPoint()
.stream()
.filter(componentInjectionPoint -> componentId.equals(componentInjectionPoint.getId()))
.findFirst()
.map(componentInjectionPoint -> componentInjectionPoint.getValueForType(componentClass))
.orElse(null);
}
public static class ComponentObjectProvider implements ObjectProvider, Provider {
private final Supplier objectSupplier;
public ComponentObjectProvider(Supplier objectSupplier) {
this.objectSupplier = objectSupplier;
}
@Nonnull
@Override
public C getObject(@Nonnull Object... args) throws BeansException {
return objectSupplier.get();
}
@Override
public C getIfAvailable() throws BeansException {
return objectSupplier.get();
}
@Override
public C getIfUnique() throws BeansException {
return objectSupplier.get();
}
@Nonnull
@Override
public C getObject() throws BeansException {
return objectSupplier.get();
}
@Override
public C get() {
return objectSupplier.get();
}
}
}