下面列出了怎么用javax.persistence.Convert的API类实例代码及写法,或者点击链接到github查看源代码。
private Converts getConverts(Element tree, XMLContext.Default defaults) {
// NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute
// properly overrides. Bit sparse, but easy...
final Map<String,Convert> convertAnnotationsMap = new HashMap<>();
if ( tree != null ) {
applyXmlDefinedConverts( tree, defaults, null, convertAnnotationsMap );
}
// NOTE : per section 12.2.3.16 of the spec <convert/> is additive, although only if "metadata-complete" is not
// specified in the XML
if ( defaults.canUseJavaAnnotations() ) {
applyPhysicalConvertAnnotations( null, convertAnnotationsMap );
}
if ( !convertAnnotationsMap.isEmpty() ) {
final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class );
groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) );
return AnnotationFactory.create( groupingDescriptor );
}
return null;
}
@SuppressWarnings("unchecked")
private AttributeConverter<Object, Object> getConverter(AccessibleObject accessible) {
Convert converter = accessible.getAnnotation(Convert.class);
if (converter != null) {
Class<?> converterClass = converter.converter();
if (!AttributeConverter.class.isAssignableFrom(converterClass)) {
throw new RuntimeException(
"Converter class must be AttributeConverter rather than " + converterClass.getName());
}
try {
Constructor<?> cs = converterClass.getDeclaredConstructor();
cs.setAccessible(true);
return (AttributeConverter<Object, Object>) cs.newInstance();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException
| InvocationTargetException e) {
throw new RuntimeException("Cannot instantiate Converter: " + converterClass.getName(), e);
}
}
return null;
}
@SuppressWarnings("unchecked")
public AttributeConversionInfo(Convert convertAnnotation, XAnnotatedElement xAnnotatedElement) {
this(
convertAnnotation.converter(),
convertAnnotation.disableConversion(),
convertAnnotation.attributeName(),
xAnnotatedElement
);
}
private Annotation getConvertsForAttribute(List<Element> elementsForProperty, XMLContext.Default defaults) {
// NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute
// properly overrides. Very sparse map, yes, but easy setup.
// todo : revisit this
// although bear in mind that this code is no longer used in 5.0...
final Map<String,Convert> convertAnnotationsMap = new HashMap<>();
for ( Element element : elementsForProperty ) {
final boolean isBasic = "basic".equals( element.getName() );
final boolean isEmbedded = "embedded".equals( element.getName() );
final boolean isElementCollection = "element-collection".equals(element.getName());
final boolean canHaveConverts = isBasic || isEmbedded || isElementCollection;
if ( !canHaveConverts ) {
continue;
}
final String attributeNamePrefix = isBasic ? null : propertyName;
applyXmlDefinedConverts( element, defaults, attributeNamePrefix, convertAnnotationsMap );
}
// NOTE : per section 12.2.3.16 of the spec <convert/> is additive, although only if "metadata-complete" is not
// specified in the XML
if ( defaults.canUseJavaAnnotations() ) {
// todo : note sure how to best handle attributeNamePrefix here
applyPhysicalConvertAnnotations( propertyName, convertAnnotationsMap );
}
if ( !convertAnnotationsMap.isEmpty() ) {
final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class );
groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) );
return AnnotationFactory.create( groupingDescriptor );
}
return null;
}
private void applyXmlDefinedConverts(
Element containingElement,
XMLContext.Default defaults,
String attributeNamePrefix,
Map<String,Convert> convertAnnotationsMap) {
final List<Element> convertElements = containingElement.elements( "convert" );
for ( Element convertElement : convertElements ) {
final AnnotationDescriptor convertAnnotationDescriptor = new AnnotationDescriptor( Convert.class );
copyStringAttribute( convertAnnotationDescriptor, convertElement, "attribute-name", false );
copyBooleanAttribute( convertAnnotationDescriptor, convertElement, "disable-conversion" );
final Attribute converterClassAttr = convertElement.attribute( "converter" );
if ( converterClassAttr != null ) {
final String converterClassName = XMLContext.buildSafeClassName(
converterClassAttr.getValue(),
defaults
);
try {
final Class converterClass = classLoaderAccess.classForName( converterClassName );
convertAnnotationDescriptor.setValue( "converter", converterClass );
}
catch (ClassLoadingException e) {
throw new AnnotationException( "Unable to find specified converter class id-class: " + converterClassName, e );
}
}
final Convert convertAnnotation = AnnotationFactory.create( convertAnnotationDescriptor );
final String qualifiedAttributeName = qualifyConverterAttributeName(
attributeNamePrefix,
convertAnnotation.attributeName()
);
convertAnnotationsMap.put( qualifiedAttributeName, convertAnnotation );
}
}
@Test
public void testDefaultEnumConverterCompatibility() {
Reflections reflections = new Reflections("com.sequenceiq",
new FieldAnnotationsScanner());
Map<String, Set<String>> incompatibleFields = new HashMap<>();
reflections.getFieldsAnnotatedWith(Convert.class).forEach(field -> {
try {
var defaultEnumConverterType = Optional.of((field.getAnnotation(Convert.class).converter()).getGenericSuperclass())
.filter(t -> ((ParameterizedType) t).getRawType().getTypeName().equals(DefaultEnumConverter.class.getTypeName()));
if (defaultEnumConverterType.isPresent()) {
boolean hasCompatibleGenericParameter = Stream.of(((ParameterizedType) defaultEnumConverterType.get()).getActualTypeArguments())
.allMatch(a -> a.getTypeName().equals(field.getType().getTypeName()));
if (!hasCompatibleGenericParameter) {
String className = field.getDeclaringClass().getName();
incompatibleFields.computeIfAbsent(className, key -> new HashSet<>()).add(field.toString());
}
}
} catch (RuntimeException e) {
// ignore if cannot check fields
}
});
Set<String> fields = new HashSet<>();
incompatibleFields.forEach((key, value) -> {
fields.add(key + ": " + String.join(", ", value));
});
Assert.assertTrue(String.format("Classes with incompatible DefaultEnumConverter: %s%s", lineSeparator(),
String.join(lineSeparator(), fields)), incompatibleFields.isEmpty());
}
private void applyLocalConvert(
Convert convertAnnotation,
XProperty collectionProperty,
Map<String,AttributeConversionInfo> elementAttributeConversionInfoMap,
Map<String,AttributeConversionInfo> keyAttributeConversionInfoMap) {
// IMPL NOTE : the rules here are quite more lenient than what JPA says. For example, JPA says
// that @Convert on a Map always needs to specify attributeName of key/value (or prefixed with
// key./value. for embedded paths). However, we try to see if conversion of either is disabled
// for whatever reason. For example, if the Map is annotated with @Enumerated the elements cannot
// be converted so any @Convert likely meant the key, so we apply it to the key
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, collectionProperty );
if ( collection.isMap() ) {
boolean specCompliant = StringHelper.isNotEmpty( info.getAttributeName() )
&& ( info.getAttributeName().startsWith( "key" )
|| info.getAttributeName().startsWith( "value" ) );
if ( !specCompliant ) {
log.nonCompliantMapConversion( collection.getRole() );
}
}
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
// the @Convert did not name an attribute...
if ( canElementBeConverted && canKeyBeConverted ) {
throw new IllegalStateException(
"@Convert placed on Map attribute [" + collection.getRole()
+ "] must define attributeName of 'key' or 'value'"
);
}
else if ( canKeyBeConverted ) {
keyAttributeConversionInfoMap.put( "", info );
}
else if ( canElementBeConverted ) {
elementAttributeConversionInfoMap.put( "", info );
}
// if neither, we should not be here...
}
else {
// the @Convert named an attribute...
// we have different "resolution rules" based on whether element and key can be converted
final String keyPath;
final String elementPath;
if ( canElementBeConverted && canKeyBeConverted ) {
keyPath = removePrefix( info.getAttributeName(), "key" );
elementPath = removePrefix( info.getAttributeName(), "value" );
if ( keyPath == null && elementPath == null ) {
// specified attributeName needs to have 'key.' or 'value.' prefix
throw new IllegalStateException(
"@Convert placed on Map attribute [" + collection.getRole()
+ "] must define attributeName of 'key' or 'value'"
);
}
}
else if ( canKeyBeConverted ) {
keyPath = removePrefix( info.getAttributeName(), "key", info.getAttributeName() );
elementPath = null;
}
else {
keyPath = null;
elementPath = removePrefix( info.getAttributeName(), "value", info.getAttributeName() );
}
if ( keyPath != null ) {
keyAttributeConversionInfoMap.put( keyPath, info );
}
else if ( elementPath != null ) {
elementAttributeConversionInfoMap.put( elementPath, info );
}
else {
// specified attributeName needs to have 'key.' or 'value.' prefix
throw new IllegalStateException(
String.format(
Locale.ROOT,
"Could not determine how to apply @Convert(attributeName='%s') to collection [%s]",
info.getAttributeName(),
collection.getRole()
)
);
}
}
}
/**
* Returns the action class ({@link MCRJobAction}).
*
* @return the action class
*/
@Column(name = "action", nullable = false)
@Convert(converter = MCRJobActionConverter.class)
public Class<? extends MCRJobAction> getAction() {
return action;
}
@Override
@Column
@Convert(converter = MCRURIConverter.class)
public URI getURI() {
return super.getURI();
}
@Column(name = "COUNTRY_CODE", length = 6)
@Convert(converter = CountryCodeConverter.class)
public CountryCode getCountryCode() {
return countryCode;
}
private static Set<Field> getAllEncryptPassword() {
Set<Field> fields = Platform.getReflections().getFieldsAnnotatedWith(Convert.class);
return fields.stream().filter(field -> field.getAnnotation(Convert.class).converter().equals(PasswordConverter.class)).collect(Collectors.toSet());
}
/**
* Gets the level. Annotated with {@code @Basic} and {@code @Enumerated(EnumType.STRING)}.
*
* @return the level.
*/
@Override
@Convert(converter = LevelAttributeConverter.class)
public Level getLevel() {
return this.getWrappedEvent().getLevel();
}
@Override
@Convert(converter = InstantAttributeConverter.class)
public Instant getInstant() {
return this.getWrappedEvent().getInstant();
}
@Override
@Convert(converter = LevelAttributeConverter.class)
@Column(name = "level")
public Level getLevel() {
return this.getWrappedEvent().getLevel();
}
@Override
@Convert(converter = MessageAttributeConverter.class)
@Column(name = "message")
public Message getMessage() {
return this.getWrappedEvent().getMessage();
}
@Override
@Convert(converter = InstantAttributeConverter.class)
@Column(name = "instant")
public Instant getInstant() {
return this.getWrappedEvent().getInstant();
}
@Override
@Convert(converter = ThrowableAttributeConverter.class)
@Column(name = "exception")
public Throwable getThrown() {
return this.getWrappedEvent().getThrown();
}
/**
* Gets the source location information. Annotated with
* {@code @Convert(converter = StackTraceElementAttributeConverter.class)}.
*
* @return the source location information.
* @see StackTraceElementAttributeConverter
*/
@Override
@Convert(converter = StackTraceElementAttributeConverter.class)
public StackTraceElement getSource() {
return this.getWrappedEvent().getSource();
}
/**
* Gets the message. Annotated with {@code @Convert(converter = MessageAttributeConverter.class)}.
*
* @return the message.
* @see MessageAttributeConverter
*/
@Override
@Convert(converter = MessageAttributeConverter.class)
public Message getMessage() {
return this.getWrappedEvent().getMessage();
}
/**
* Gets the marker. Annotated with {@code @Convert(converter = MarkerAttributeConverter.class)}.
*
* @return the marker.
* @see MarkerAttributeConverter
*/
@Override
@Convert(converter = MarkerAttributeConverter.class)
public Marker getMarker() {
return this.getWrappedEvent().getMarker();
}
/**
* Gets the exception logged. Annotated with {@code @Convert(converter = ThrowableAttributeConverter.class)}.
*
* @return the exception logged.
* @see ThrowableAttributeConverter
*/
@Override
@Convert(converter = ThrowableAttributeConverter.class)
public Throwable getThrown() {
return this.getWrappedEvent().getThrown();
}
/**
* Gets the context stack. Annotated with {@code @Convert(converter = ContextStackAttributeConverter.class)}.
*
* @return the context stack.
* @see ContextStackAttributeConverter
* @see org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter
*/
@Override
@Convert(converter = ContextStackAttributeConverter.class)
public ThreadContext.ContextStack getContextStack() {
return this.getWrappedEvent().getContextStack();
}