0

I keep getting this message that Spring will override MY factory bean definition with the CassandraRepositoryFactoryBean. This is causing problems as the reason I am overriding the factory is to override the save method on a repo so that I can automatically populate createTimestamp and updateTimestamp methods.

2018-01-16 18:24:32,355  INFO main o.s.b.f.s.DefaultListableBeanFactory:828 - Overriding bean definition for bean 'containerIdRepo' with a different definition: replacing [Root bean: class [com.database.repo.audit.TimestampCrudRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]

Obviously there is either some order of precedence or missing configuration here but I can't find it. Perhaps you can?

My Spring Configuration:

@Configuration
@EnableCassandraRepositories(repositoryFactoryBeanClass = TimestampCrudRepositoryFactoryBean.class, repositoryBaseClass = TimestampCrudRepositoryImpl.class, basePackages = {
    "com.database.repo", "com.database.entity" })
public class DataCassandraConfiguration extends CassandraConfiguration {

@Bean
@Primary
@Order(Ordered.HIGHEST_PRECEDENCE)
public CassandraTemplate cassandraTemplate(Session session, CassandraConverter converter) {
    return new CassandraTemplate(session, converter);
}

}

Where I override the TypedIdCassandraRepository

@NoRepositoryBean
public interface TimestampCrudRepository<T extends BaseTimestampEntity, I extends Serializable>
    extends TypedIdCassandraRepository<T, I> {


}

If you're curious about the BaseTimestampEntity

public abstract class BaseTimestampEntity {

@CreatedDate
@Column("create_timestamp") // timestamp,
private Instant createTimestamp;
@LastModifiedDate
@Column("update_timestamp") // timestamp,
private Instant updateTimestamp;

}

Where I implement the save method:

@NoRepositoryBean
@Slf4j
public class TimestampCrudRepositoryImpl<T extends BaseAuditEntity, I extends Serializable>
    extends SimpleCassandraRepository<T, I> implements TimestampCrudRepository<T, I> {

private final boolean isPrimaryKeyEntity;

public TimeStampCrudRepositoryImpl(CassandraEntityInformation<T, I> metadata, CassandraOperations operations) {
    super(metadata, operations);
    this.isPrimaryKeyEntity = metadata.isPrimaryKeyEntity();
}

@Override
public <S extends T> S save(S entity) {
    log.info("Using overriden save method to add create and update timestamp");
    Assert.notNull(entity, "Entity must not be null");

    Instant now = Instant.now();

    entity.setUpdateTimestamp(now);

    if (entity.getCreateTimestamp() == null) {
        entity.setCreateTimestamp(now);
    }

    if (entityInformation.isNew(entity) || isPrimaryKeyEntity) {
        return operations.insert(entity);
    }

    return operations.update(entity);
}
}

And finally my factory:

public class TimestampCrudRepositoryFactoryBean<T extends TimestampCrudRepository<S, I>, S extends BaseTimestampEntity, I extends Serializable>
    extends RepositoryFactoryBeanSupport<T, S, I> {

@Autowired
private CassandraTemplate cassandraTemplate;

protected TimestampCrudRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
    super(repositoryInterface);
}

public void setCassandraTemplate(CassandraTemplate cassandraTemplate) {
    this.cassandraTemplate = cassandraTemplate;
}

@Override
protected RepositoryFactorySupport createRepositoryFactory() {
    return new TimestampCrudRepositoryFactory(cassandraTemplate);
}

@Override
public void afterPropertiesSet() {
    super.afterPropertiesSet();
    Preconditions.checkNotNull(cassandraTemplate, "cassandraTemplate must not be null!");
    setMappingContext(cassandraTemplate.getConverter().getMappingContext());
}


private static class TimestampCrudRepositoryFactory<S extends BaseAuditEntity, I extends Serializable>
        extends CassandraRepositoryFactory {

    private final CassandraTemplate cassandraTemplate;

    public TimestampCrudRepositoryFactory(CassandraTemplate cassandraTemplate) {
        super(cassandraTemplate);
        this.cassandraTemplate = cassandraTemplate;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected Object getTargetRepository(RepositoryInformation information) {
        CassandraEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());

        return new TimestampCrudRepositoryImpl(entityInformation, cassandraTemplate);
    }

    @Override
    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
        return TimestampCrudRepositoryImpl.class;
    }

}
}

Almost forgot the repo:

public interface ContainerIdRepo extends TimestampCrudRepository<ContainerEntity, MapId> {}

Nothing is bombing out but the updateTimestamp and createTimestamp inserts into the Cassandra DB are null and I can tell the override save method is not being hit when debugging.

Justin
  • 859
  • 4
  • 15
  • 30

1 Answers1

1

Turns out

@EnableCassandraRepositories(repositoryFactoryBeanClass = TimestampCrudRepositoryFactoryBean.class, repositoryBaseClass = TimestampCrudRepositoryImpl.class, basePackages = {
"com.database.repo", "com.database.entity" })

and

@Bean
@Primary
@Order(Ordered.HIGHEST_PRECEDENCE)
public CassandraTemplate cassandraTemplate(Session session, CassandraConverter converter) {
return new CassandraTemplate(session, converter);
}

Can't live in a separate configuration java class even though the class is annotated with @Configuration. I had to put it in the main application class.

Additionally I had to just delete the factory I created. The TimestampCrudRepositoryFactoryBean

With just the interface and the implementation (and once the annotation was moved) it just worked and Spring didn't try and replace my definition with the more generic one.

Figure it was an order of operations thing with Spring config. At least that's my educated guess.

Justin
  • 859
  • 4
  • 15
  • 30