DynamoDBMapperConfigFactory.java
/*
* Copyright © 2018 spring-data-dynamodb (https://github.com/prasanna0586/spring-data-dynamodb)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.socialsignin.spring.data.dynamodb.repository.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.socialsignin.spring.data.dynamodb.core.TableNameResolver;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
/**
* Factory for creating TableNameResolver instances for SDK v2.
* <p>
* Replaces the SDK v1 DynamoDBMapperConfigFactory. In SDK v2, table name resolution
* is simplified and no longer requires the complex configuration that DynamoDBMapperConfig provided.
* <p>
* If a user-defined {@link TableNameResolver} bean exists in the application context,
* it will be used. Otherwise, a default resolver that returns the base table name unchanged
* will be provided.
*
* @deprecated This factory is provided for backward compatibility. Consider injecting
* TableNameResolver directly or using a custom configuration class.
*/
@Deprecated
public class DynamoDBMapperConfigFactory implements FactoryBean<TableNameResolver>, BeanFactoryAware, BeanNameAware {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDBMapperConfigFactory.class);
/**
* User-defined TableNameResolver bean, if available.
*/
@Nullable
private TableNameResolver tableNameResolver;
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Nullable
private String ownBeanName;
/**
* Default constructor for DynamoDBMapperConfigFactory.
*/
public DynamoDBMapperConfigFactory() {
}
@Override
public void setBeanName(@NonNull String name) {
this.ownBeanName = name;
}
@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
/**
* Sets the TableNameResolver to use. Called programmatically for testing.
*
* @param tableNameResolver the user-defined TableNameResolver, or null if none exists
*/
public void setTableNameResolver(@Nullable TableNameResolver tableNameResolver) {
this.tableNameResolver = tableNameResolver;
if (tableNameResolver != null) {
LOGGER.debug("Using user-defined TableNameResolver: {}", tableNameResolver.getClass().getName());
}
}
/**
* Default TableNameResolver that returns the base table name unchanged.
*/
private static final TableNameResolver DEFAULT = new TableNameResolver() {
@Override
public <T> String resolveTableName(Class<T> domainClass, String baseTableName) {
return baseTableName;
}
};
/**
* Looks up user-defined TableNameResolver beans from the application context.
* This method avoids circular reference issues by scanning bean definitions
* instead of instantiating beans.
*/
@Nullable
private TableNameResolver lookupUserDefinedResolver() {
if (beanFactory == null) {
return null;
}
// Scan bean definitions to find user-defined TableNameResolver beans
// without triggering bean instantiation that would cause circular references
String[] beanNames = beanFactory.getBeanNamesForType(TableNameResolver.class, false, false);
for (String beanName : beanNames) {
// Skip our own bean (the FactoryBean creates a bean with the same name)
if (beanName.equals(ownBeanName)) {
continue;
}
// Check if this is a FactoryBean-produced bean by checking for the & prefix
// FactoryBeans register themselves with & prefix for the factory, and without for the product
if (beanFactory.containsBean("&" + beanName)) {
// This is a FactoryBean-produced bean, check if it's our FactoryBean type
Object factoryBean = beanFactory.getBean("&" + beanName);
if (factoryBean instanceof DynamoDBMapperConfigFactory) {
// Skip beans produced by our own factory type
continue;
}
}
// Check if this is a real bean definition (not a FactoryBean product)
BeanDefinition beanDef = beanFactory.containsBeanDefinition(beanName)
? beanFactory.getBeanDefinition(beanName)
: null;
if (beanDef != null) {
String beanClassName = beanDef.getBeanClassName();
// Skip if this is a DynamoDBMapperConfigFactory
if (beanClassName != null && beanClassName.equals(DynamoDBMapperConfigFactory.class.getName())) {
continue;
}
}
// This looks like a user-defined TableNameResolver, try to get it
try {
TableNameResolver resolver = beanFactory.getBean(beanName, TableNameResolver.class);
LOGGER.debug("Found user-defined TableNameResolver bean '{}': {}", beanName, resolver.getClass().getName());
return resolver;
} catch (Exception e) {
LOGGER.trace("Could not get TableNameResolver bean '{}': {}", beanName, e.getMessage());
}
}
return null;
}
@Override
@Nullable
public TableNameResolver getObject() {
// First check if explicitly set (for testing)
if (tableNameResolver != null) {
return tableNameResolver;
}
// Look up from application context
TableNameResolver resolved = lookupUserDefinedResolver();
if (resolved != null) {
return resolved;
}
LOGGER.debug("No user-defined TableNameResolver found, using default (no-op) resolver");
return DEFAULT;
}
@Override
public Class<?> getObjectType() {
return TableNameResolver.class;
}
}