1

I have encountered a very strange exception when I was learning AOP in Spring.

Here are my codes:

CompactDisc Interface:

public interface CompactDisc {
    void play();
}

BlankDisc class:

import org.springframework.stereotype.Component;
import java.util.List;

@Component
public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List<String> tracks;

    public BlankDisc(String title, String artist, List<String> tracks) {
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
    }

    @Override
    public void play() {
        System.out.println("Playing "+title+" by "+artist);
        for (String track : tracks)
            System.out.println("-Track "+track);
    }

    public void playTrack(int trackNumber) {
        System.out.println("-Track "+tracks.get(trackNumber));
    }

TrackCounter class

package soundsystem;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import java.util.HashMap;
import java.util.Map;

@Aspect
public class TrackCounter {
    private Map<Integer,Integer> trackCounts = new HashMap<>();

    @Pointcut("execution(* BlankDisc.playTrack(int)) " +
            "&& args(trackNumber)")
    public void trackPlayed(int trackNumber) {}

    @Before("trackPlayed(trackNumber)")
    public void countTrack(int trackNumber) {
        int currentCount = getPlayCount(trackNumber);
        trackCounts.put(trackNumber, currentCount + 1);
    }

    public int getPlayCount(int trackNumber) {
        return trackCounts.getOrDefault(trackNumber, 0);
    }
}

TrackCounterConfig class

package soundsystem;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

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

@Configuration
@EnableAspectJAutoProxy
public class TrackCounterConfig {
    @Bean(name = "compactDisc")
    public BlankDisc blankDisc() {
        List<String> list= new ArrayList<>(5);
        list.add("Sgt.Pepper's Lonely Hearts Club Band");
        list.add("With a Little Help from My Friends");
        list.add("Lucy in the Sky with Diamonds");
        list.add("Getting Better");
        list.add("Fixing a Hole");

        return new BlankDisc("Sgt.Pepper's Lonely Hearts Club Band","The Beatles",list);
    }

    @Bean
    public TrackCounter trackCounter() {
        return new TrackCounter();
    }
}

TrackCounterTest class:

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import soundsystem.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TrackCounterConfig.class)
public class TrackCounterTest {
    @Autowired
    private BlankDisc cd;

    @Autowired
    private TrackCounter counter;

    @Test
    public void testTrackCounter() {
        //Question: cd must be CompactDisc not BlankDisc,
        //otherwise will cause type exception, why?
        cd.playTrack(0);
        cd.playTrack(1);
        cd.playTrack(2);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(4);

        assertEquals(1,counter.getPlayCount(1));
        assertEquals(1,counter.getPlayCount(0));
        assertEquals(1,counter.getPlayCount(2));
        assertEquals(4,counter.getPlayCount(3));
        assertEquals(1,counter.getPlayCount(4));
    }
}

I ran the test,then I had the exception:

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'compactDisc' is expected to be of type 'soundsystem.BlankDisc' but was actually of type 'com.sun.proxy.$Proxy22'
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1510)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1489)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)

The problems are:

1.If I change the type of cd in TrackCounterTest from BlankDisc to CompactDisc, the exception will not occur, why?

2.After the first problem being solved, if I haven't declared the method void playTrack(int) in the interface CompactDisc, the assertEquals() in test class will fail. That is, AOP does not work, why?

I have been spent a whole day working on this problem and after searching on the google I still could not be able to find the answer. Since I am a rookie in Spring, I sincerely hope that someone could help me to figure this out.

Thank you!!!

zRegle
  • 57
  • 4

1 Answers1

0

This issue is because of autowiring the bean of type class instead do for implemented interface: Please check this stackoverflow link which explains the same issue:

BeanNotOfRequiredTypeException issue stackoverflow explanation

Mithun Theertha
  • 131
  • 2
  • 6