JSF ManagedProperty not working for class - spring

Sorry for my English. I want to set #ManagedProperty for class TaskBO, but it is not works. TaskMB class:
#ManagedBean(name="taskMB")
#RequestScoped
public class TaskMB implements Serializable {
#ManagedProperty(value="#{TaskBO}")
public TaskBO taskBO;
public TaskBO getTaskBO() {
return this.taskBO;
}
public void setTaskBO(TaskBO taskBO){
this.taskBO = taskBO;
}
//...
}
It prints the error:
javax.servlet.ServletException: Unable to set property taskBO for managed bean taskMB
javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert com.otv.model.bo.TaskBO#6c80b8 of type class $Proxy135 to class com.otv.model.bo.TaskBO
But if I add interface ITaskBO, that it is works:
#ManagedProperty(value="#{TaskBO}")
public ITaskBO taskBO;
public ITaskBO getTaskBO() {
return this.taskBO;
}
public void setTaskBO(ITaskBO taskBO){
this.taskBO = taskBO;
}
Why not work #ManagedProperty with the class TaskBO?

Is best pratice wire interface instead of concrete class to prevent the problem you encountered.
Cannot convert com.otv.model.bo.TaskBO#6c80b8 of type class $Proxy135
to class com.otv.model.bo.TaskBO
Often Spring's managed object are proxied and a java proxy can be casted ONLY to interface and not to concrete class; the error above is generated because:
TaskBO object is managed by Spring and proxied to an object of type $Proxy135 (the real type of your object now is not really concrete class TaskBO but a proxy you can cast to ITaskBO, the $Proxy135)
you are trying to do some like public TaskBO taskBO = (TaskBO)$Proxy135; but cast a proxy to concrete class is impossible
The right way is to write public ITaskBO taskBO = (ITaskBO)$Proxy135; and this works because a proxy can be cast only to interface
Avoid - as much as possible - use of concrete class in favor of interface.
In addiction you can look here if you are mixing configuration how described in linked question.

Related

Spring - generic superclass not instantiated properly?

ATM I am in the middle of refactoring our Selenium E2E Test Framework to use Spring.
My class/bean:
package info.fingo.selenium.utils.driver;
#Component
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ProxyDecorator extends WebDriverDecorator<WebDriver> {
#Autowired
public ProxyDecorator(TestUtils testUtils, DriverManager driverManager) {
super(WebDriver.class);
this.testUtils = testUtils;
this.driverManager = driverManager;
Superclass:
package org.openqa.selenium.support.decorators;
public class WebDriverDecorator<T extends WebDriver> {
private final Class<T> targetWebDriverClass;
private Decorated<T> decorated;
#SuppressWarnings("unchecked")
public WebDriverDecorator() {
this((Class<T>) WebDriver.class);
}
public WebDriverDecorator(Class<T> targetClass) {
this.targetWebDriverClass = targetClass;
}
public final T decorate(T original) {
Require.nonNull("WebDriver", original);
decorated = createDecorated(original);
return createProxy(decorated, targetWebDriverClass);
}
Issue occures on calling this line:
createProxy(decorated, targetWebDriverClass)
Where targetWebDriverClass for unknown reason is null and NullPointerException is later thrown.
This should not EVER happen as targetWebDriverClass is ALWAYS set through constructor - either provided by client (calling super(class)) or defaulted to WebDriver.class in default WebDriverDecorator constructor. Worked fine without Spring, and unfortunately I don't understand Spring enough to get any information through debugging.
My Spring dependencies:
ext.springVersion = '2.7.1'
dependencies {
//SPRING BOOT
api "org.springframework.boot:spring-boot-starter:$springVersion",
"org.springframework.boot:spring-boot-starter-aop:$springVersion",
"org.springframework.boot:spring-boot-starter-test:$springVersion",
decorate method in superclass WebDriverDecorator in marked as final which makes it ineligible for Spring CGLIB proxying as it cannot proxy final methods (& classes) - Sorry, I don't know exact reason why this caused my issue.
This is not my own class, it is taken from inside of dependency so I cannot change this.
This means that this class cannot be managed by Spring. In order for this to somehow work I get rid of inheritance (extends keyword) and replace it with composition. Got to do some reflection magic (for one of its protected method) but this seems to do the trick.

Spring Boot WebFlux Converter

I am trying to migrate my project from the Spring MVC to the Spring WebFlux.
The repository I am currently using is ReactiveCrudRepository.
In order to achieve the post-redirect-get pattern, which I have used within Spring MVC, I need to rewrite the current converter to work with ReactiveCrudRepository.
I was trying to do that with this aproach:
#Component
public class ObjByIdConverter implements Converter<String, Obj> {
#Autowired
private IObjRepository objRepository;
#Override
public Obj convert(String id) {
return objRepository.findById(id).block();
}
}
When I implement converter in this way, I am getting the following error:
block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-xxx.
When I was using CrudRepository instead of ReactiveCrudRepository everything was worked fine.
Is there a way to implement converter to work with ReactiveCrudRepository?
~~~ Edit 1 ~~~
The controller class:
#PostMapping
public Mono<String> processOrder(#ModelAttribute("newCar") Car car) {
webDataBinder.validate();
BindingResult bindingResult = webDataBinder.getBindingResult();
if (bindingResult.hasErrors()) {
return Mono.just("orderForm");
}
return this.carRepository.save(car).thenReturn("redirect:/");
}
The model class:
#Document(collection = "cars")
#ToString
#EqualsAndHashCode
public class Car {
#Id
private String id;
private List<Obj> objs = new ArrayList<>();
// constructor, getters, setters, ...
}
I am using the Thymeleaf view technology.
I have to provide the implementation for ObjByIdConverter because I am getting the following error message: [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'objs'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.app.model.Obj' for property 'objs[0]': no matching editors or conversion strategy found]
You should not use block in any case in reactive development. If you have ReactiveRepository and Spring Webflux, use them together with Mono/Flux from repository to controller to leverage the reactive way of doing.
But I think the main reason why you try to convert the result to a standard type is for the post-redirect-get pattern, could you detail this in the spring controller context ?

Filtering OSGi services using SlingScriptHelper#getService() method

I want to instantiate a service object in my jsp using sling taglib. In normal scenario where the service class is being implemented by only 1 class, its pretty simple:-
RegistrationService registrationService = sling.getService(RegistrationService.class);
But if the service class has more than 1 implementation classes, then how can we make sure to instantiate object for a particular class.
My java class are like:-
1. Interface: RegistrationService
2. Implementation Class 1:-
#Properties({#Property(name = "datasource", value = "SBWS"})
#Service
public class RegistrationServiceImpl implements RegistrationService{
}
3. Implementation Class 2:-
#Properties({#Property(name = "datasource", value = "SOLR"})
#Service
public class RegistrationServiceImpl implements RegistrationService{
}
How can I make sure that using
RegistrationService registrationService = sling.getService(RegistrationService.class);
in jsp will instantiate service for let say implementation class 1
Use SlingScriptHelper#getServices(...) method, which allows to specify a filter:
RegistrationService[] services = sling.getServices(RegistrationService.class, "(datasource=SBWS)");
if (services.length > 0) {
// services[0] contains your service
}
Getting OSGi service and filtering it via properties is quite low-level stuff, consider moving it from JSP to a Java class.

CDI events and generics

I'm trying to send events and do this generically. I mean - create one abstract base DAO class with generic type and fire the event from its method. This should work for all descendants. This works if I define the exact type, but doesn't - if I use generics. What I mean:
AbstractDAO (with generics - doesn't fire the event):
public abstract class AbstractDAO<T extends Persistable> implements Serializable {
#Inject #PostSaveEvent Event<T> postSaveEvent;
public T saveOrUpdate(T object) throws DatabaseException {
T obj = em.merge(object);
postSaveEvent.fire(obj);
}
}
AbstractDAO (no generics, just simple class cast - fires the event):
public abstract class AbstractDAO<T extends Persistable> implements Serializable {
#Inject #PostSaveEvent Event<Polis> postSaveEvent;
public T saveOrUpdate(T object) throws DatabaseException {
T obj = em.merge(object);
postSaveEvent.fire((Polis)obj);
}
}
PolisDAO class, which extends AbstractDAO and defines the generic type:
#Stateless
#Named
#PolisType
public class PolisDAO extends AbstractDAO<Polis> {
// some methods (saveOrUpdate is not overriden!)
}
My observer class:
#Stateless
#Named
public class ProlongationService {
public void attachProlongationToPolisOnSave(#Observes #PostSaveEvent Polis polis) throws DatabaseException {
// ... DO smth with polis object. This is NOT called in the first case and called in the second
}
THis is very strange for me, as "fire()" method for CDI event should define the event type on runtime, not during compilation or deployment... When I debug, I see, that
postSaveEvent.fire(obj);
from the first sample operates exactly with Polis entity. But no event is fired nevertheless...
Upd. I tried the base generic class, but no luck:
#Inject #PostSaveEvent Event<Persistable> postSaveEvent;
Thanks.
This should, in theory, work, however in practice inspecting the type of generic objects at runtime with Java Reflection is, at times, impossible. This is due to type erasure. IIRC the type of the concrete sub class isn't erased, so it should be possible to reconnect this, but I guess the implementation isn't doing this right now.
File this as a bug in the http://issues.jboss.org/browse/WELD issue tracker (if you are using Weld), with the classes you provide as an example and we can try to fix it.
To work around, try injecting the event into the concrete subclass, and passing it as an argument, or using an accessor method, to get it into the abstract super class.

Util class for accesing a Service in Spring 3

In Spring 3 it is not possible to set #Autowired in either static fields or methods, so since I want to declare an utility class such as:
public class SchoolYearServiceUtil {
private static SchoolYearService schoolYearService;
public static SchoolYear getSchoolYear(Long id) {
return schoolYearService.get(id);
}
}
to avoid having to inject the schoolYearService everywhere (jsp, command class...) in which I need it. In this case, I don't need an interface to be implemented by SchoolYearServiceUtil.
I don't want to have to initialize the object through code but getting the same instance as the Spring's one.
Which would be the best option to implement the getSchoolYear as a static method?
Thanks.
Would this be conceptually wrong?:
#Component
public class SchoolYearServiceUtil {
private static SchoolYearService schoolYearService;
#Autowired(required = true)
private SchoolYearServiceUtil(#Qualifier("schoolYearServiceImpl") SchoolYearService schoolYearService) {
SchoolYearServiceUtil.schoolYearService = schoolYearService;
}
public static SchoolYearService getSchoolYearService() {
return schoolYearService;
}
public static SchoolYear getSchoolYear(Long id) {
return getSchoolYearService().get(id);
}
}
I would have to make sure that only Spring calls once the constructor and the constructor is called nowhere else, that's why I declared the constructor as private.
I fully support skaffman's comment. You don't need static fields with DI. You just define a bean of scope singleton (default).
There is a way to obtain a bean statically, but you should be aware that it is not to be used in regular situations. (there are some valid applications). It is to use the WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
You notice that you need to pass a ServletContext argument.

Resources