How to Log all the methods public method calls in AOP - spring-boot

I have some issue in Logging all the methods when a service calls. Code is like this:
package com.myproject.controller;
#RestController(/person)
public class Controller{
public Person getpersonInfo(){
......
getValidPerson();
}
}
public Person getValidPerson() {
isPersonValid(Person person);
....
}
Person class Methods :
package com.myproject.dao;
public class Dao{
public boolean isPersonValid(){
//Checks for the person is Valid
}
}
Aspect Class :
package com.myproject;
#Component
#Aspect
public class Logging{
#Before("execution(* com.myproject..*.*(..)))")
public void beforeServiceCall(Jointpoint jp) {
//Some Logging function
}
}
Main class like this
package com.myproject;
#SpringBootApplication
#EnableAutoConfiguration
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAspectJAutoProxy()
public class Main implements LoadTimeWeavingConfigurer{
public static void main(String[] args){
......
}
}
Pom file :
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-instrument -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.1</version>
</dependency>
When I call the service http://localhost:8080/person - GET
getpersonInfo() is only Logged in this case, I have also tried
LTW , but do not solve
I need to log all internal methods to the service like is getValidPerson(),isPersonValid() mentioning all arguments to those invoked method.

Related

Powermock calling actual private method instead of mocking

I want to mock the private method "downloadFromNexus" but instead of mocking, actual method gets called while trying to mock here PowerMockito.doReturn("").when(spy, "downloadFromNexus", "", "");
#Component(value = "DownloadXFile")
#Order(1)
#Slf4j
public class DownloadXFile implements DownloadJarFiles {
#Value("${path}")
private String path;
#Override
public void download() throws IOException {
....
downloadFromNexus(path, outputFilePath);
log.info("jar {} downloaded", jar);
}
private void downloadFromNexus(final String url, final String outputFilePath) throws IOException {
FileUtils.copyURLToFile(
new URL(url),
new File(outputFilePath),
2000,
2000);
}
}
Test
#RunWith(PowerMockRunner.class)
#PrepareForTest(DownloadXFile.class)
#SpringBootTest(classes = DownloadXFile.class)
class DownloadXTest {
#Autowired
DownloadXFile downloadXFile;
#Test
public void test() throws Exception {
final DownloadXFilespy = PowerMockito.spy(downloadXFile);
PowerMockito.doReturn("").when(spy, "downloadFromNexus", "", "");
downloadXFile.download();
PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke("downloadFromNexus");
}
}
pom.xml
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>1.6.6</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.0.42-beta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
You called downloadXFile.download(); on original object instead of the spy.

Custom annotation with Spring AOP as a library is not working

I am trying to create a spring boot library with Custom annotation and Spring AOP. When I used this library with new spring boot application. Then Its not working. Even I am not getting any error.
Library Sample -
Custom Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface HttpLogger {
}
Spring AOP class
#Aspect
class LoggingAspect {
#Around("#annotation(com.demo.commonlogging.aspect.HttpLogger)")
public Object inControllers(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return loggingAdvice(proceedingJoinPoint); // Method for implementation
}
}
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Using mvn clean install for creating library
Now new library is imported in springboot application.
And new Custom annotation is used in controllers
Controllers
#RestController
#RequestMapping(value = "/rest/test")
public class RestApiTestControllers {
#GetMapping
#HttpLogger
public String get(){
return "Hello !";
}
}
Please help here.
Seems like you are missing #Component from LoggingAspect also make call to proceed proceedingJoinPoint.proceed(); and return it's value.
So your code should look like:
#Aspect
#Component
class LoggingAspect {
#Around("#annotation(com.demo.commonlogging.aspect.HttpLogger)")
public Object inControllers(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Before call");
Object returned = proceedingJoinPoint.proceed();
System.out.println("After call");
return returned;
}
}
Hope this helps!

Request method of type post not recognized by Spring Rest Api

This Code work fine :
#RestController
#RequestMapping("/api/post")
public class PostController {
#Autowired
private PostService postService;
public PostService getPostService() {
return postService;
}
public void setPostService(PostService postService) {
this.postService = postService;
}
#RequestMapping(value = "/userPost", method = RequestMethod.GET)
#ResponseBody
public String userPost(String username) {
try {
List<Validation> validations = new ArrayList<Validation>();
ValidationHandeler.rejectIfEmptyOrWhitespace(validations, username, "username is requierd");
if (validations.isEmpty()) {
List<Post> followers = getPostService().findUserPost(username);
return new Message(followers, MessageSuccesStatusEnum.SUCCESS).toString();
}
return new Message(validations, MessageSuccesStatusEnum.FAILED).toString();
} catch (Exception ex) {
return new Message("Error retriving follower list : " + ex.toString(), MessageSuccesStatusEnum.FAILED)
.toString();
}
}
and this is the output :
{"result":"0","info":["username is requierd"]}
but when ever I change the RequestMethod type to post it give me the following output :
{"timestamp":1492948640973,"status":404,"error":"Not Found","message":"No message available","path":"/api/post/userPost"}
does any body know how to fix this problem?
Looks like you are using GET instead of POST as a request method.
#RequestMapping(value = "/userPost", method = RequestMethod.GET)
<dependencies>
<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.0.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.rest-assured/json-schema-validator -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
TestClass TestNG
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import static io.restassured.RestAssured.*;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
public class basics {
#Test
public void getPlaceAPI()
{
RestAssured.baseURI = "https://maps.googleapis.com";
given().param("location", "42.3675294,-71.186966").param("radius",
"10000").param("key", "").when()
.get("/maps/api/place/textsearch/json").then().assertThat().statusCode(200);
}
}

How to enable basic caching with Spring Data JPA

I am trying to enable basic caching with Spring Data JPA. But I cannot understand why the DAO methods are still querying the database instead of using the cache.
Given the following Spring Boot 1.5.1 application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
#SpringBootApplication
#EnableCaching
public class Server{
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
Controller
#Controller
public class PasswordsController {
#Autowired
private PasswordService service;
#SuppressWarnings("unchecked")
#RequestMapping("/passwords.htm")
public void passwords(Map model,
HttpServletRequest request) {
model.put("passwords", service.getPasswords(request));
}
...
Service
#Service
#Transactional
public class PasswordService extends BaseService {
#Autowired
private PasswordJpaDao passwordDao;
public Collection<Password> getPasswords(HttpServletRequest request) {
Collection<Password> passwords = passwordDao.getPasswords(params);
return passwords;
}
...
Interface
#Transactional
public interface PasswordJpaDaoCustom {
public Collection<Password> getPasswords(PasswordSearchParameters params);
}
and implementation
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import com.crm.entity.Password;
import com.crm.search.PasswordSearchParameters;
#Transactional
#Repository
public class PasswordJpaDaoImpl implements PasswordJpaDaoCustom {
#PersistenceContext
private EntityManager em;
#Override
#Cacheable("passwords")
public Collection<Password> getPasswords(PasswordSearchParameters params) {
System.err.println("got here");
return em.createQuery(hql, Password.class);
}
...
Maven Dependencies
<!-- Spring Boot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Spring Boot end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
I understand that Spring Boot will implicitly use ConcurrentHashMap for caching without any specific configuration necessary?
But the getPasswords() dao method is always called instead of using the cache. Why is this?
Yes, spring boot by default uses ConcurrentHashMap for caching and the issue with your code is that you did not set any key for your passwords cache, so it is calling the database every time for fetching the data.
So you need to the key (any unique identifier) using the params object variables as shown below:
#Cacheable(value="passwords", key="#params.id")//any unique identifier
public Collection<Password> getPasswords(PasswordSearchParameters params) {
System.err.println("got here");
return em.createQuery(hql, Password.class);
}

Jersey setup without web.xml

I'm attempting to set up a simple REST web application that uses Jersey. In the documentation, it seems that I should be able to create my application without using a web.xml file. From the site:
JAX-RS provides a deployment agnostic abstract class Application for declaring root resource and provider classes, and root resource and provider singleton instances. A Web service may extend this class to declare root resource and provider classes.
The example that follows shows this code:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorldResource.class);
return s;
}
}
To me, this says that I can use an Application class to do all of my servlet setup. This seems to be the configuration that reads my resource class's annotations and sets up the correct URL handling mechanisms. Is that correct? I don't have to do any other setup?
I ask because I created the following and it didn't work (I get a 404 from localhost:8080/{context}/test):
pom.xml:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
Application class:
#ApplicationPath("/")
public class JerseyTestApp extends Application
{
#Override
public Set<Class<?>> getClasses()
{
final Set<Class<?>> classes = new HashSet<>();
classes.add(JerseyTestController.class);
return classes;
}
}
Resource class:
#Path("/test")
public class JerseyTestController
{
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getTestMsg()
{
return "It works";
}
}
Dumb. All I had to do was include the jersey-servlet jar, as prescribed by this answer.

Resources