Search code examples
javaaopaspectjaspectj-maven-plugin

Convert Inter-Type declaraton from .aj to .java with Aspect annotations


I have this situation. This is my Village.java:

public class Village{

    private Integer vid;
    private String villageName;
    private String district;

    public Integer getVid() {
        return vid;
    }
    public void setVid(Integer vid) {
        this.vid = vid;
    }
    public String getVillageName() {
        return villageName;
    }
    public void setVillageName(String villageName) {
        this.villageName = villageName;
    }
    public String getDistrict() {
        return district;
    }
    public void setDistrict(String district) {
        this.district = district;
    }
}

This is my Dao.java interface:

public interface Dao<T> {
    public void insert();
    public void update();
    public void delete();
}

This is my aspect Village_Dao.aj (you can just ignore the static methods logic):

import org.apache.ibatis.session.SqlSession;
import com.madx.finance.data.utils.persistence.Dao;
import com.madx.finance.data.utils.factory.ConnectionFactory;

public aspect Village_Dao {
    declare parents: Village implements Dao<Village>;

    public void Village.insert() {
        Village.insertVillage(this);
    }

    public void Village.update() {
        Village.updateVillage(this);
    }

    public void Village.delete() {
        Village.deleteVillage(this.getVid());
    }

    public Village Village.getData() {
        return Village.getDataVillage(this.getVid());
    }

    public static void Village.insertVillage(Village village) {
        SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
        VillageMapper mapper = session.getMapper(VillageMapper.class);
        mapper.insertVillage(village);
        session.commit();
        session.close();
    }

    public static void Village.updateVillage(Village village) {
        SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
        VillageMapper mapper = session.getMapper(VillageMapper.class);
        mapper.updateVillage(village);
        session.commit();
        session.close();
    }

    public static void Village.deleteVillage(Integer id) {
        SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
        VillageMapper mapper = session.getMapper(VillageMapper.class);
        mapper.deleteVillage(id);
        session.commit();
        session.close();
    }

    public static Village Village.getDataVillage(Integer id) {
        SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
        VillageMapper mapper = session.getMapper(VillageMapper.class);
        Village village = mapper.selectVillage(id);
        session.close();
        return village;
    }
}

I'm trying without success to convert the Village_Dao.aj to an annotated version Village_Dao_Java.java. I just managed to make the class implements Dao but I can't manage to write the methods (insert, update e delete separately in this file Village_Dao_Java.java).

This is version (still not complete) of the Village_Dao_Java.java (I read this link but I couldn't get it work for this case):

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;

import com.madx.finance.data.utils.persistence.Dao;

@Aspect
public class Village_Dao_Java {

    @DeclareParents("com.madx.demo.Village")
    private Dao<Village> implementedInterface;
}

Solution

  • What you want is not possible with @AspectJ style, you need to use the more powerful native syntax. (Why do you want to switch anyway?)

    The reason behind this is that the Java compiler can only convert @DeclareParents to a form in which Village is a subclass of whatever interface implementation you define in your aspect, for example something like this:

    @Aspect
    public class Village_Dao_Java {
        public static class VillageDao implements Dao<Village> {
            @Override
            public void insert() {
                Village.insertVillage(this);
            }
    
            @Override
            public void update() {
                Village.updateVillage(this);
            }
    
            @Override
            public void delete() {
                Village.deleteVillage(this.getVid());
            }
    
            public Village getData() {
                return getDataVillage(this.getVid());
            }
    
        }
    
        @DeclareParents(
            value = "de.scrum_master.app.Village",
            defaultImpl = VillageDao.class
        )
        private Dao<Village> villageDao;
    }
    

    But this approach has several problems:

    • The methods try to access static methods from the future VillageDao subclass Village, so you cannot declare the static methods in VillageDao but have to declare them in Village directly.
    • If instead you would declare them directly in VillageDao you could call them e.g. via VillageDao.insertVillage(this), but then the signature public static void insertVillage(Village village) would no longer fit because this is a VillageDao, not its own subclass Village.
    • For similar reasons you cannot call this.getVid() because this is a VillageDao and not a Village, but the getter method has a fixed signature in the original Village class.

    And so forth. The Java compiler just is not powerful enough to do what the AspectJ compiler does: weave code right into the original class files.

    Ergo: Please stick with native syntax. Not only is it more powerful but IMO also more readable. I never understood why so many people try to coax the powerful AspectJ into the poor alternative @AspectJ syntax. Somehow they seem to believe that they get a gain from pure Java syntax. I disagree. They just get a degradation of technical means and bad syntax never meant to be used for full-fledged AOP.