2

I'm using Spring AOP with AspectJ and Spring Data MongoDb and am having a world of trouble persisting objects.

In this case, I have an AclEntryDaoImpl that exposes AclEntryImpl. When AclEntryImpl is provided a Principal that is a standard Java object (a "non-Spring" bean), mongoTemplate.save() works as expected. However when Principal is a Spring bean, Mongo is unable to convert the object and results in a MappingException org.springframework.data.mapping.model.MappingException: No id property found on class class com.sun.proxy.$Proxy33. All my objects need to be Spring beans so that (a) I keep my objects decoupled and (b) my AOP (LoggingAspect) is invoked.

Lastly, I cannot take advantage of Spring converters because Mongo sees the target object AclEntryImpl as a proxy com.sun.proxy.$Proxy33 and so Converter<Principal, DBObject> is never invoked.

Any and all help would be greatly appreciated!

Snippets:

Here's my Spring XML configuration:

<beans>
    <context:component-scan base-package="a.b" />
    <context:property-placeholder location="config.properties" />
    <aop:aspectj-autoproxy />

    <bean id="loggingAspect" class="a.b.LoggingAspect" />

    <mongo:db-factory host="${database.host}" port="${database.port}" dbname="${database.dbname}" />

    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
    </bean>

    <bean id="aclEntryDao" class="a.b.AclEntryDaoImpl">
        <lookup-method name="createAclEntry" bean="aclEntry" />
    </bean>

</beans>

AclEntryImpl:

@Document
@Component
@Scope("prototype")
public class AclEntryImpl implements AclEntry {

    @Id
    private String id;

    private String service;

    @DBRef @Expose
    private Principal principal;

    @Expose
    private boolean accessGranted;

    @Expose
    private List<Permission> permissions;

    @Override @Loggable @MongoSaveReturned
    public AclEntry save() {
        return this;
    }

    ...getters and setters...

}

AclEntryDaoImpl:

@Repository
public abstract class AclEntryDaoImpl implements AclEntryDao {

    @Override @Loggable
    public AclEntry addEntry(String serviceName, Principal principal, Permission[] permissions, boolean accessGranted) throws Exception {
        AclEntry entry = createAclEntry(); //<-- Spring lookup-method
        entry.setService(serviceName);
        entry.setPrincipal(principal); //<-- com.sun.proxy.$Proxy33
        entry.setAccessGranted(accessGranted);
        for (Permission permission : permissions) {
            if (!entry.addPermission(permission)) {
                return null;
            }
        }
        return entry.save();
    }

    ... other DAO methods ...

}

LoggingAspect:

@Aspect
public class LoggingAspect {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Pointcut("execution(!void a.b..*.*(..))")
    public void returningMethods() {}

    @AfterReturning(pointcut="returningMethods() && @annotation(MongoSaveReturned)", returning="retVal")
    public Object mongoSaveReturnedAdvice(Object retVal) {
        Logger logger = null;
        try {
            logger = getLogger(retVal);
            mongoTemplate.save(retVal); //<-- throws MappingException
            log(logger, "save:    " + retVal.toString());
        } catch (Exception e) {
            log(logger, "throw:   " + e.toString());
        }
        return retVal;
    }

    ... other logging methods ...

}
4

0 回答 0