Using #Validated causing CastException in Spring - java

I am using Spring 3.1.
I am trying to use Bean-Validator to validate a method.
My class:
#Named
#Scope("prototype")
#Validated
public class MyClass implements someClass
{
..
#Override
public void handle(#NotNull MyObj myObj) {
..
}
}
Now this is the calling class:
#Named
public class CallingClass{
..
#Inject
Provider<MyClass> myClass;
public void doSomething(Myobj myObj)
{
MyClass handler = myClass.get(); //here I get the exception
myClass.handle(myObj);
}
That's the exception:
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy85 cannot be cast to com...MyClass
Any idea?
thanks,
ray.

try to put #Validated and constraints on parameters to your interface if the object is not pojo.

Related

How to specify which version of a concrete implementation for an abstract class to autowire in Spring?

Having the following class structure:
public abstract class A {
String someProperty = "property"
public abstract void doSomething();
}
#Service
public class Aa extends A {
#Override
public abstract void doSomething() {
System.out.println("I did");
}
}
#Service
public class Ab extends A {
#Override
public abstract void doSomething() {
System.out.println("I did something else");
}
}
I need a way to tell Spring which A concrete class to Autowire in my Foo service, based on a property in a properties file.
#Service
public class Foo {
#Autowire
private A assignMeAConcreteClass;
}
And in my properties file I have this:
should-Aa-be-used: {true, false}
Remove the #Service annotation, instead write a #Bean-annotated method in a configuration class that reads the properties, and returns the appropriate A instance.
Not a new way but in your case I think that a possible suitable way would be to use
FactoryBean in the class that wants to inject the bean conditionally.
The idea is simple : you implement FactoryBean by parameterizing it with the interface of the bean that you want to inject and override getObject() to inject the wished implementation :
public class FactoryBeanA implements FactoryBean<A> {
#Autowired
private ApplicationContext applicationContext;
#Value("${should-Aa-be-used}")
private boolean shouldBeUsed;
#Override
public A getObject() {
if (shouldBeUsed) {
return applicationContext.getBean(Aa.class));
return applicationContext.getBean(Ab.class));
}
}
But FactoryBean instances are not classic beans. You have to configure it specifically.
You could configure it in a Spring Java configuration in this way :
#Configuration
public class FactoryBeanAConfiguration{
#Bean(name = "factoryBeanA")
public FactoryBeanA factoryBeanA() {
return new FactoryBeanA();
}
#Bean
public beanA() throws Exception {
return factoryBeanA().getObject();
}
}

Spring inherited #Component with constructor arguments

I have a service which needs to create Agents on the runtime. Agents inherit from a base Agent class. I would like to use the Autowired ability of spring instead of doing my own dependency injections.
But I am running into this issue, even though I am marking the component as scope=prototype, and even #Lazy to prevent anything from happening at compile-time.
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.my.project.AgentType1 required a bean of type 'com.my.project.POJO' that could not be found.
This is the service that tries to create the agents:
#Service
public class ProjectMain {
#Autowired
ApplicationContext context;
List<IAgent> agents = new ArrayList<>();
void SetupAgents(List<POJO> agentPojos) {
for(POJO agentPojo: agentPojos) {
IAgent agent = AgentFactory.CreateAgent(agentPojo, context);
agents.add(agent);
}
}
}
This is the factory class, not marked as #Component etc. It uses the context passed to it to create the child class beans. It tries to pass the constructor argument via the getBean method.
public class AgentFactory {
public static IAgent CreateAgent(POJO agentPojo, ApplicationContext context) {
if (agentPojo.type.equals("AgentType1")) {
return context.getBean(AgentType1.class, agentPojo);
} else {
return context.getBean(AgentType2.class, agentPojo);
}
}
}
This is a custom annotation which I found is needed for inheritance scenarios.
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Component
#Inherited
#Lazy
#Scope("prototype")
public #interface AgentAnnotation {}
These are the base and child agent classes, which need a custom data structure called POJO to work.
#AgentAnnotation
public class BaseAgent implements IAgent {
#Autowired
Environment env;
public BaseAgent(POJO agentPojo, String someotherdata) {
}
}
public class AgentType1 extends BaseAgent {
public AgentType1(POJO agentPojo) {
super(agentPojo, "mydata1");
...
}
}
public class AgentType2 extends BaseAgent {
public AgentType2(POJO agentPojo) {
super(agentPojo, "mydata2");
...
}
}
This is the starter app.
#ComponentScan(basePackages = "com.my.project", includeFilters = #ComponentScan.Filter(AgentAnnotation.class))
#EnableScheduling
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I also tried the configuration approach:
#Configuration
public class BaseAgentConfig {
#Bean
#Scope("prototype")
public AgentType1 agentType1(POJO agentPojo) {
return new AgentType1(agentPojo);
}
#Bean
#Scope("prototype")
public AgentType2 agentType2(POJO agentPojo) {
return new AgentType2(agentPojo);
}
}
In this case, I removed the #AgentAnnotation from the baseAgent class as we are now instantiating through this config. Also removed the ComponentScan line from the main App.
This time around, the #Autowired doesn't work. All Autowired references in the baseAgent class are null.
Please advise on the best approach to solve this error. Thanks.
Found the issue and solution.
Basically, I was expecting child classes to inherit #Component and #Scope, which it doesn't.
So essentially, I need to annotate each child class with #Component and #Scope("prototype").
The other problem was that I was expecting Autowired items in the constructor, which was too early. Adding a #PostConstruct addressed that issue.
So I ended up deleting the custom annotation and the configuration class and making the changes I just described.

How can I inject member annotations into my current instantiated object using Guice?

I am trying to inject a custom annotation using the Guice bindInterceptor into my currently instantiated Service.java class. Unfortunately when I call myMethod() the OnAnnotationEvent::invoke method is not called. How can I use Guice to call OnAnnotationEvent::invoke when the #OnAnnotation annotation tag is used on a method in the current class?
My code looks like this:
Service.java
//Instantiated by another service
public class Service extends AbstractVerticle {
private DataAccess dataAccess;
#Inject
public void setDataAccess(DataAccess dataAccess){
this.dataAccess = dataAccess;
}
#Override
public void start() throws Exception {
Guice.createInjector(new DataAccessModule()).injectMembers(this);
myMethod();
}
#MyAnnotation
public void myMethod() {
dataAccess.doStuff();
}
}
DataAccessModule.java
public class DataAccessModule extends AbstractModule {
#Override
protected void configure() {
OnAnnotationEvent onAnnotationEvent = new OnAnnotationEvent();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), onAnnotationEvent);
bind(DataAcess.class).to(DataAccessImpl.class);
}
}
OnAnnotationEvent
public class OnAnnotationEvent implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Annotation called on: " + invocation.getMethod().getName();
return invocation.proceed();
}
}
MyAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {}
I think that your problem is that you creating new injector that does not knows anything about your class. If you just need injector in your class - use #Inject private Injector injector;. If you need to load some aditional modules locally you just need to create child injector :
#Inject private baseInjector;
...
injector = baseInjector.createChildInjector(new Module1(),new Moddule2());
This doesn't work because your Service instance isn't managed by Guice. To make it work you must either create Service with Guice or annotate method doStuff in DataAccessImpl with MyAnnotation.

#RequestBody with generic type

I'm having some problem with Spring MVC 4.2.6 and Jackson (2.7.3). I created an absctract #RestController class with a method that uses a generic type. I implement this abstract class passing the type of generic object. I use #RequestBody and the DispatcherServlet throws JsonMappingException (can not construct instance of my class). The MappingJackson2HttpMessageConverter in application context is configured.
Edit: More info added.
public abstract class AbsctractAnimalResource<DTO extends AnimalDTO> {
// Doesn't work. Throws JsonMappingException. (#RequestBody)
#RequestMapping(value = "/bar", method = POST, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<?> bar(#RequestBody DTO dto) throws Exception {
return new ResponseEntity(dto, HttpStatus.CREATED);
}
}
#RestController
#RequestMapping("/cat")
public class CatResource extends AbsctractAnimalResource<CatDTO> {
}
#RestController
#RequestMapping("/dog")
public class DogResource extends AbsctractAnimalResource<DogDTO> {
}
interface AnimalDTO { }
public class CatDTO implements AnimalDTO { }
public class DogDTO implements AnimalDTO { }
After some debugs in Spring 4.2.6 classes I found this commentary:
https://github.com/spring-projects/spring-framework/blob/4.2.x/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java#L51
Spring 4.2.X and Jackson 2.7.X don't work together. I downgraded my Jackson version to 2.6.6 and now everything works. Spring 4.3.X works well with Jackson 2.7+.

How to #autowire some bean into JsonSerializer?

I am using lazy loading with hibernate in my web app.
I would like to load some objects from the database at the parsing stage of the server response
#Component
public class DesignSerializer extends JsonSerializer<Design> {
#Autowired
IDesignService designService; <-- is null
}
Which is totally understandable because DesignSerializer is being instantiated with the "new" operator for each object.
I am sure there is a way to inject my bean into that serializer when ever it is created, I just don't know how.
Can you guys help me or point me in the right direction.
Solution is SpringBeanAutowiringSupport if you are using Spring Framework 2.5+.
public class DesignSerializer extends JsonSerializer<Design> {
#Autowired
IDesignService designService;
}
public DesignSerializer(){
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
...
}
I Hope that help you
We had the same problem with JsonSerializer and Spring autowiring. The solution that worked for us was to make two constructors. One for Spring which sets the dependency as a static field, and another one that is used by the Jackson initialisation.
This works because the Spring dependency injection (autowiring) happens before Jackson initialises the serializer.
#Component
public class MyCustomSerializer extends JsonSerializer<String> {
private static IDesignService designService;
// Required by Jackson annotation to instantiate the serializer
public MyCustomSerializer() { }
#Autowired
public MyCustomSerializer(IDesignService designService) {
this.designService = designService;
}
#Override
public void serialize(String m, JsonGenerator gen, SerializerProvider s) {
gen.writeObject(MyCustomSerializer.designService.method(..));
}
}
I Solved the problem by creating a static field in a different bean and then #Autowire its setter method.
#Service("ToolBox")
#Transactional
public class ToolBox
{
static Logger logger = Logger.getLogger(ToolBox.class);
private static IService service;
#Autowired
public void setService(IService service)
{
ToolBox.service = service;
}
public static IService getService()
{
return ToolBox.service;
}}
like shown in this thread: Can you use #Autowired with static fields?

Categories