Custom Java annotation processor for AST in incremental compilation - java

I have this scenario: two maven modules (jdk6) A and B.
In module A I've defined these classes:
MyBeanAnnotation : an annotation for classes defined like this:
package x.y.z;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.TYPE)
public #interface MyBeanAnnotation {
String name();
}
MyAnnProcessor: a class extending AbstractProcessor defined like this:
package x.y.z;
import java.io.File;
import java.util.Date;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
#SupportedAnnotationTypes("x.y.z.MyBeanAnnotation")
#SupportedSourceVersion(SourceVersion.RELEASE_6)
public class MyAnnProcessor extends AbstractProcessor{
#Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Hello World!");
}
return true;
}
}
I've created a text file in META-INF/services named javax.annotation.processing.Processor
x.y.z.MyAnnProcessor
I can compile it, no problem.
In the module B:
pom.xml : created a dependency to module A
I've created a class MyAnnotatedBean annotated with MyBeanAnnotation
package x.y.z;
import x.y.z.MyBeanAnnotation;
#MyBeanAnnotation(name = "scemochileggee")
public class MyAnnotatedBean {
private String qweq = "qweq";
}
When I compile B from scratch (e.g. mvn clean install), the processor MyAnnProcessror gets correctly called, and I can see the printout in the compiler logs
On the other hand, when I edit it in Netbeans (I've only tried this IDE) and save the MyAnnotatedBean file, nothing happens and the MyAnnProcessor in not invoked.
Do you have any idea if there's a way to make MyProcessor work in incremental compilation as well?
Thanks in advance.

Related

Why the Pointcut expression is not working

If i keep #Pointcut("within(org.example.ShoppingCart.*)") in AuthenticationAspect.java then the authenticate method is NOT getting invoked BUT when i change to #Pointcut("within(org.example..*)") then it does get invoked.
Doesn't the 2nd PointCut below automatically include the first one?
#Pointcut("within(org.example.ShoppingCart.*)")
#Pointcut("within(org.example..*)")
i believe both of these should work.
Following is the code :
ShoppingCart.java
package org.example;
import org.springframework.stereotype.Component;
#Component
public class ShoppingCart {
public void checkout(String status)
{
System.out.println("Checkout method called");
}
}
AuthenticationAspect.java
package org.example;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class AuthenticationAspect {
#Pointcut("within(org.example.ShoppingCart.*)")
public void authenticationPointCut()
{
}
#Before("authenticationPointCut()")
public void authenticate()
{
System.out.println("Authentication is being performed");
}
}
Main.java
package org.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
ShoppingCart cart = context.getBean(ShoppingCart.class);
cart.checkout("CANCELLED");
}
}
BeanConfig.java
package org.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration // Indicates this is a configuration class
#ComponentScan(basePackages = "org.example") // Indicates where to find the components/beans
#EnableAspectJAutoProxy // Enables the AspectJ features in project
public class BeanConfig {
}
i am learning spring aspect and unsure why the pointcut expression is not working .
Since the within pointcut designator limits matching to join points of certain types, the problem is your pointcut expression is matching types within ShoppingCart because of .* in the end. If you remove those characters it should work.
#Pointcut("within(org.example.ShoppingCart)")
public void authenticationPointCut(){}

Consider defining a bean of type 'com.example.filter.FilterDao' in your configuration

I am trying to connect spring boot application with MySQL for that I have created a interface with name FilterDao which extend JpaRepository class. but whenever I try to make object of implemented class in Service I got this error "Consider defining a bean of type 'com.example.filter.FilterDao' in your configuration" as I am new to spring boot I don't understand this error.
FilterApplication.java
package com.example.filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class FilterApplication {
public static void main(String[] args) {
SpringApplication.run(FilterApplication.class, args);
}
}
FilterDao.java
package com.example.filter;
import com.example.filter.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.FluentQuery;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
//#Configuration
public interface FilterDao extends JpaRepository<Filter, Integer> {
}
FilterService.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class FilterService {
#Autowired
private FilterDao filterDao;
public List<Filter> getData() {
System.out.println("----------------------HERE-------------");
return filterDao.findAll();
}
}
FilterConnector.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class FilterConnector {
#Autowired
private FilterService filterService;
#GetMapping("/home")
public List<Filter> home()
{
return this.filterService.getData();
}
}
Project Structure
Annotate FilterDao with #Repository
Seems spring has not created bean for FilterDao repository and you are trying to use that`
#Autowired
private FilterDao filterDao;`
There might different reasons for this exception. Please try the below solution.
Use #EnableJpaRepositories(basePackages = "com.example.filter") with your FilterApplication class.
Use #ComponentScan(basePackages = "com.example.*") with FilterApplication class
Use #Repoitory annotation with FilterDao interface.
Hope this helps. For more details check the below tutorial.
https://javatute.com/jpa/consider-defining-a-bean-of-type-in-your-configuration/

Java - Spring boot - could not autowire - no beans found

I have a Data Loader Class which is suppose to load data once the app starts.
My Error -
Could not autowire. No beans of 'OwnerService' Found.
However, my ownerService class is annotated as I have shown below -
This is the class whose supposed to do that -
DataLoader
import model.Owner;
import model.Vet;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import services.OwnerService;
import services.VetService;
import services.map.OwnerServiceMap;
import services.map.VetServiceMap;
#Component
public class DataLoader implements CommandLineRunner {
private final OwnerService ownerService;
private final VetService vetService;
public DataLoader(OwnerService ownerService, VetService vetService) {
this.ownerService = ownerService;
this.vetService = vetService;
}
OwnerServiceMap
package services.map;
import model.Owner;
import org.springframework.stereotype.Service;
import services.OwnerService;
import java.util.Set;
#Service
public class OwnerServiceMap extends AbstractMapService<Owner,Long> implements OwnerService
{//some code here}
The vetService is the same as ownerService.
My applcation class -
package petclinic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class PetclinicApplication {
public static void main(String[] args) {
SpringApplication.run(PetclinicApplication.class, args);
}
}
Maybe I have hierarchy problems, as the application class doesn't search for beans in enough places in the project?
Thank you!

AspectJ not executing the advice

I am trying to understand how AspectJ works so I built this very simple example. I can execute x() from a web browser but applaud() never gets executed. Why? How can I get it executed (apart from calling it inside x())? I am trying to do all this without creating an xml.
My environment is Java, Spring, AspectJ, IntelliJ and Windows 10.
package hello;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Aspect
#Configuration
#EnableAspectJAutoProxy
public class SomeClass {
#RequestMapping("/x")
#Pointcut("execution(* hello.SomeClass.x())")
public String x() {
System.out.println("in x");
return "<div><h1>Some content</h1></div>";
}
#After("hello.SomeClass.x()")
public void applaud() {
System.out.println("CLAPCLAPCLAPCLAPCLAP");
}
}

JBoss RESTeasy JAX-RS JAXB schema validation with Decorator

I am trying to validate all incoming XML files that come over my (contract first) REST interface in an application running inside JBoss AS 7. I have written a #Decorator for Pretty-Printing (as by the example in the JBoss RESTeasy documentation) and an analogous one for switching on XML schema validation for the unmarshaller. Unfortunately, the decorator for the unmarshaller is never called.
Here is the code for the Pretty Decorator:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Marshaller;
import org.jboss.resteasy.annotations.Decorator;
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Decorator(processor = PrettyProcessor.class, target = Marshaller.class)
public #interface Pretty {}
And the implementation:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
#DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> {
private static final Logger LOGGER = Logger.getLogger(PrettyProcessor.class);
#Override
public Marshaller decorate(Marshaller target, Pretty annotation, Class type, Annotation[] annotations, MediaType mediaType) {
LOGGER.debug("Pretty.");
try {
target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
} catch (PropertyException e) {
}
return target;
}
}
Now the annotation for the Validate (that does not work):
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Unmarshaller;
import org.jboss.resteasy.annotations.Decorator;
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Decorator(processor = ValidateProcessor.class, target = Unmarshaller.class)
public #interface Validate {}
The implementation:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import javax.xml.XMLConstants;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
import org.xml.sax.SAXException;
#DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class ValidateProcessor implements DecoratorProcessor<Unmarshaller, Validate> {
private static final Logger LOGGER = Logger.getLogger(ValidateProcessor.class);
#Override
public Unmarshaller decorate(Unmarshaller target, Validate annotation, Class type, Annotation[] annotations, MediaType mediaType) {
target.setSchema(getSchema());
LOGGER.debug("Set validation schema.");
System.out.println("Set validation schema.");
return target;
}
}
And the code of the REST interface:
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.xml.ws.WebServiceException;
#Path("/{mdvt}/{ouid}/order")
public interface OrderResource {
#RolesAllowed({ "mpa" })
#POST
#Path("/update")
#Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
#Produces(MediaType.APPLICATION_XML)
#Pretty
public Response update(#Context SecurityContext sec,
#PathParam("ouid") String ouID,
#PathParam("mdvt") long masterDataVersionTag,
#Validate UpdateOrdersRequest uor) throws WebServiceException;
}
On the same REST method, (update) the #Pretty Decorator gets called while the #Validate does not. What am I doing wrong here?
I have found an old bug Decorator for Jaxb unmarshaller doesn't work which is closed.
The comments there say that everything works, and the code above is almost exactly the one from there, including the solution. Nevertheless, nothing works for the Unmarshaller.
Finally this problem was resolved for JBoss AS 7.
The problem lies in the Resteasy implementation which is buggy until version 2.3.5.Final.
See https://issues.jboss.org/browse/RESTEASY-711 but ignore the mentioned workaround, it does not work until version 2.3.5.
The working solution is to download the Restwasy distribution version 2.3.5.Final or above, extract it and look for resteasy-jboss-modules-2.3.5.Final.zip
Extract this file in the root of JBoss AS 7.1.1 and resteasy will be updated to the new version. After this step, all of the above code just works.
Thanks to Bill Burke to point me to the solution,
You could implement a MessageBodyReader that sets an Schema on the JAXB Unmarshaller to perform validation. For sample code check out my answer to a similar question:
Validate JAXBElement in JPA/JAX-RS Web Service

Categories