我一直在评估为project采用spring-data-mongodb。总之,我的目标是:
这里需要注意的是ExtensionType包含protected List<Object> any;
,允许它存储任何类的对象。就我而言,它属于名为TSD Module_Name_Here ModuleType的类,可以浏览here
使用spring-data-mongodb作为持久性存储
这是使用简单的ProductDataRepository
实现的@RepositoryRestResource(collectionResourceRel = "product", path = "product")
public interface ProductDataRepository extends MongoRepository<TSDProductDataType, String> {
TSDProductDataType queryByGtin(@Param("gtin") String gtin);
}
然而,未编组的 TSDProductDataType 包含JAXBElement,spring-data-mongodb似乎无法自行处理并抛出CodecConfigurationException org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Class.
这是错误的陈述:
TSDProductDataType tsdProductDataType = jaxbElement.getValue();
repository.save(tsdProductDataType);
我尝试使用转换器为spring-data-mongodb解释here,然而,似乎我遗漏了一些东西,因为异常是关于&#34; Codecs&#34;而不是&#34;转换器&#34;。
感谢任何帮助。
编辑:
为JAXBElement添加转换器
注意:适用于org.springframework.boot :: spring-boot-starter-parent的1.5.6.RELEASE版本。随着版本2.0.0.M3,地狱崩溃
似乎我在尝试提前添加转换器时遗漏了一些东西。所以,我把它添加到下面进行测试:
@Component
@ReadingConverter
public class JAXBElementReadConverter implements Converter<DBObject, JAXBElement> {
//@Autowired
//MongoConverter converter;
@Override
public JAXBElement convert(DBObject dbObject) {
Class declaredType, scope;
QName name = qNameFromString((String)dbObject.get("name"));
Object rawValue = dbObject.get("value");
try {
declaredType = Class.forName((String)dbObject.get("declaredType"));
} catch (ClassNotFoundException e) {
if (rawValue.getClass().isArray()) declaredType = List.class;
else declaredType = LinkedHashMap.class;
}
try {
scope = Class.forName((String) dbObject.get("scope"));
} catch (ClassNotFoundException e) {
scope = JAXBElement.GlobalScope.class;
}
//Object value = rawValue instanceof DBObject ? converter.read(declaredType, (DBObject) rawValue) : rawValue;
Object value = "TODO";
return new JAXBElement(name, declaredType, scope, value);
}
QName qNameFromString(String s) {
String[] parts = s.split("[{}]");
if (parts.length > 2) return new QName(parts[1], parts[2], parts[0]);
if (parts.length == 1) return new QName(parts[0]);
return new QName("undef");
}
}
@Component
@WritingConverter
public class JAXBElementWriteConverter implements Converter<JAXBElement, DBObject> {
//@Autowired
//MongoConverter converter;
@Override
public DBObject convert(JAXBElement jaxbElement) {
DBObject dbObject = new BasicDBObject();
dbObject.put("name", qNameToString(jaxbElement.getName()));
dbObject.put("declaredType", jaxbElement.getDeclaredType().getName());
dbObject.put("scope", jaxbElement.getScope().getCanonicalName());
//dbObject.put("value", converter.convertToMongoType(jaxbElement.getValue()));
dbObject.put("value", "TODO");
dbObject.put("_class", JAXBElement.class.getName());
return dbObject;
}
public String qNameToString(QName name) {
if (name.getNamespaceURI() == XMLConstants.NULL_NS_URI) return name.getLocalPart();
return name.getPrefix() + '{' + name.getNamespaceURI() + '}' + name.getLocalPart();
}
}
@SpringBootApplication
public class TsdApplication {
public static void main(String[] args) {
SpringApplication.run(TsdApplication.class, args);
}
@Bean
public CustomConversions customConversions() {
return new CustomConversions(Arrays.asList(
new JAXBElementReadConverter(),
new JAXBElementWriteConverter()
));
}
}
到目前为止一切顺利。但是,如何实例化MongoConverter converter;
?
MongoConverter
是一个接口,所以我想我需要一个坚持这个接口的可实例化类。有什么建议吗?
答案 0 :(得分:1)
我理解为了方便起见,只需将现有的域对象映射到没有样板的数据库层,但即使你没有JAXB类结构问题,我仍然建议不要使用它逐字。除非这是一个简单的一次性项目,否则您几乎肯定会遇到域模型需要更改的问题,但您的持久数据需要保持在现有状态。如果您只是直接持久化数据,则无法在较新的域架构和较旧的持久数据方案之间进行转换。持久化数据方案的版本化也是明智的。
您发布的用于编写客户转换器的链接是实现此目的的一种方式,可以很好地适应Spring生态系统。该方法还应该解决您遇到的问题(关于底层凌乱的JAXB数据结构不能干净地转换)。
您无法使该方法有效吗?确保您使用@Component
加上自动类扫描或通过某些Configuration
类手动将它们加载到Spring上下文中。
编辑以解决您的编辑:
将以下内容添加到每个转换器中:
private final MongoConverter converter;
public JAXBElement____Converter(MongoConverter converter) {
this.converter = converter;
}
尝试将bean定义更改为:
@Bean
public CustomConversions customConversions(@Lazy MongoConverter converter) {
return new CustomConversions(Arrays.asList(
new JAXBElementReadConverter(converter),
new JAXBElementWriteConverter(converter)
));
}