Search code examples
spring-bootaspectjpointcut

Simple Aspect not Executing


I had this Aspect working then all of a sudden it stopped. @AfterThrowing all classes in and below the pointcut. You can see I added a constructor to the Aspect to ensure it is picked up by Spring and it is. Below is a class that I stepped through and watched exceptions thrown and handled. Just throwing (no pun intended) this out there to see if any one notices something.

package mil.ndms.taabatch.af.batchjobs.afdaily.difmsjon;

import java.util.ArrayList;
import java.util.List;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.transform.Range;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;

import mil.ndms.taabatch.af.batchjobs._jobscommon.FileUtilities;
import mil.ndms.taabatch.af.customexceptions.StepException;

@Service
public class DIFMSJonReader implements ItemReader<DIFMSJonModel>, StepExecutionListener
{   
    private int nextItemIndex;
    private List<DIFMSJonModel> difmsJonModelList;
    private StepExecution stepExecutionForRead;
    
    @Autowired
    FileUtilities fileUtilities;

    @Override
    /*
     * This code in the beforeStep method is required here because this is a custom ItemReader.
     * Custom readers need to produce their own list to be iterated over.
     * Each item in the List invokes the read method.
     */
    public void beforeStep(StepExecution stepExecution)
    { 
        // Initialize Class variables
        stepExecutionForRead = stepExecution; 
        difmsJonModelList = new ArrayList<DIFMSJonModel>();
        nextItemIndex = 0;
        
        // Create Flat File Reader
        FlatFileItemReader<DIFMSJonModel> reader = null;
        
        try
        {
            // Get the file location from the BATCH_FILE_PARAMETERS Table
            String fileName = fileUtilities.getFileInputLocation("MS204D01.DAT");
            
            // Throw Exception if the location is not found
            if(null == fileName)
                throw new StepException("File - MS204D01 - Does not exist");

            // Build the Flat FileRreader based on the following parameters 
            reader = 
                new FlatFileItemReaderBuilder<DIFMSJonModel>()
                    .name("DIFMSJonReader").linesToSkip(0)
                    .resource(new FileSystemResource(fileName))
                    .fixedLength()
                    .columns(new Range[] { new Range(1, 12), new Range(13, 13), new Range(14, 14), new Range(15, 21) })
                    .names(new String[] { "jon", "completeIndicator", "laborValid", "jonOpenDate" })
                    .targetType(DIFMSJonModel.class)
                    .build();
    
            // Open the file/reader assign it to a context
            reader.open(new ExecutionContext());
            
            // Iterate over the open file.  Each row will be assigned to a new instance of DIFMSJonModel
            // and then stored in the difmsJonModelList
            DIFMSJonModel item;
            while ((item = (DIFMSJonModel) reader.read()) != null)
            {
                difmsJonModelList.add(item);
            }
        } 
        catch (Exception e)
        {
            // if this exception is not of type StepException and since we are in a Job Step, 
            // we are going to add a StepExecution to the Exception to be used by the Aspect which will 
            // log the exception
            if(!(e instanceof StepException))
            {
                StepException se = new StepException(e);
                se.setStepExecution(stepExecution);
                e.addSuppressed(new StepException(e));
            }
            else
            {
                ((StepException) e).setStepExecution(stepExecution);
            }
            // We must empty the List so that the read() has nothing to read
            // This is how we stop the Job
            difmsJonModelList.clear();
            stepExecution.getJobExecution().setStatus(BatchStatus.FAILED);
        }
        finally
        {
            // Close the reader/file
            if(null != reader) reader.close();
        }
    }
    
    @Override
    public DIFMSJonModel read() 
        throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException
    {
        DIFMSJonModel nextItem = null;

        try
        {
            /* Counter **********************************************************************
             * This code is necessary because this is a custom ItemReader.
             * This "counter" lets us know which item is next to retrieve from the list.
             * Once this method ends the item is passed to the ItemProcessor method
             */
            if (nextItemIndex < difmsJonModelList.size())
            {
                nextItem = difmsJonModelList.get(nextItemIndex);
                nextItemIndex++;
            } 
            else
            {
                nextItemIndex = 0;
            }
            /* Counter **********************************************************************/
        }
        catch (Exception e)
        {
            if(!(e instanceof StepException))
            {
                StepException se = new StepException(e);
                se.setStepExecution(stepExecutionForRead);
                e.addSuppressed(se);
            }
            else
            {
                ((StepException) e).setStepExecution(stepExecutionForRead);
            }
            
            // After we process an Exception we must throw the Exception.
            // Spring Batch sees the Exception and stops the Job
            throw e;
        }
        
        return nextItem;
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {  return stepExecution.getExitStatus();  }
}
package mil.ndms.taabatch.af.aspects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;

import mil.ndms.taabatch.af.customexceptions.StepException;

@Aspect
@Configuration
public class ExcepetionAspect
{
    public ExcepetionAspect()
    {
        System.out.println("");
        System.out.println("This is the Aspect");
        System.out.println("");
    }
    
    @AfterThrowing(pointcut = "execution(* mil.ndms.taabatch.af.batchjobs..*.*(..))", throwing = "e")
    public void logException(JoinPoint jp, Throwable e) throws Throwable
    {
        String name = e.getClass().toString().substring(e.getClass().toString().lastIndexOf(".")+1);
        switch(name)
        {
            case "Exception":
            {
                Throwable[] se = e.getSuppressed();
                StepException exception = (null != se && null != se[0] && se[0] instanceof StepException) 
                        ? null : (StepException) se[0];
                if(null != exception) logStepException(jp, exception); else logOtherException(jp, e);
            }
            case "StepException": logStepException(jp, (StepException) e);
            default: logOtherException(jp, e);
        }
    }
        
    private void logStepException(JoinPoint joinPoint, StepException e )
    {
        final Signature signature = joinPoint.getSignature();
        final Class<?> clazz = signature.getDeclaringType();
        final Logger logger = LoggerFactory.getLogger(clazz);
        
        logger.error("The following Step has errors -  " + "[step-name:{}]", e.getStepExecution().getStepName());
        e.getStepExecution().getFailureExceptions().forEach(th -> logger.error(th.getMessage()));
       
        return;
    }
    
    private void logOtherException(JoinPoint joinPoint, Throwable e )
    {
        final Signature signature = joinPoint.getSignature();
        final Class<?> clazz = signature.getDeclaringType();
        final Logger logger = LoggerFactory.getLogger(clazz);
        
        logger.error(e.getMessage());
       
        return;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.5</version>
        <relativePath/>
    </parent>
    
    <groupId>mil.ndms.taabatch.af</groupId>
    <artifactId>taaBatch</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
    
    <name>taaBatch</name>
    <description>TAA Batch Application</description>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
    
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Solution

  • My method did not throw and exception. It was handled internally so Spring see it. Thanks to -kriegaex