Skip to content

#107 - hibernate-models-bytebuddy #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions buildSrc/src/main/groovy/shared-testing.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ plugins {
// Wire in the shared-tests
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// link the
configurations {
sharedTestClasses {
canBeConsumed = false
Expand All @@ -24,22 +23,20 @@ configurations {
sharedTestRuntimeClasspath {
canBeConsumed = false
canBeResolved = true
extendsFrom testRuntimeClasspath
}
}

dependencies {
testImplementation project( ":hibernate-models-testing" )

sharedTestClasses project(path: ':hibernate-models', configuration: 'exposedTestClasses')
sharedTestResources project(path: ':hibernate-models', configuration: 'exposedTestResources')
sharedTestRuntimeClasspath project(path: ':hibernate-models', configuration: 'exposedTestRuntimeClasspath')
sharedTestClasses project(path: ':hibernate-models', configuration: 'exportedTestClasses')
sharedTestResources project(path: ':hibernate-models', configuration: 'exportedTestResources')

sharedTestRuntimeClasspath project(path: ':hibernate-models', configuration: 'exportedTestRuntimeClasspath')
}

tasks.named( "test", Test ) {
// use the configurations defined above, which depends on the configurations in `:architecture-tests`
testClassesDirs += configurations.sharedTestClasses

classpath += configurations.sharedTestResources
classpath += configurations.sharedTestRuntimeClasspath
}
16 changes: 16 additions & 0 deletions hibernate-models-bytebuddy/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id "published-java-module"
id "shared-testing"
}

description = "Support for hibernate-models based on ByteBuddy (isolated dependency)"

repositories {
mavenCentral()
}

dependencies {
api project( ":hibernate-models" )

implementation libs.byteBuddy
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.bytebuddy;

/**
* Settings for hibernate-models ByteBuddy support
*
* @author Steve Ebersole
*/
public interface Settings {
/**
* Used to pass the ByteBuddy {@linkplain net.bytebuddy.pool.TypePool}.
*/
String TYPE_POOL_PARAM = "hibernate.models.bytebuddy.typePool";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.bytebuddy.internal;

import java.lang.annotation.Annotation;
import java.util.Map;

import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext;
import org.hibernate.models.internal.AnnotationTargetSupport;

import net.bytebuddy.description.annotation.AnnotationSource;

/**
* @author Steve Ebersole
*/
public abstract class AbstractAnnotationTarget implements AnnotationTargetSupport {
private final ByteBuddyModelsContext modelContext;

private Map<Class<? extends Annotation>, ? extends Annotation> usageMap;

public AbstractAnnotationTarget(ByteBuddyModelsContext modelContext) {
this.modelContext = modelContext;
}

public ByteBuddyModelsContext getModelContext() {
return modelContext;
}

protected abstract AnnotationSource getAnnotationSource();

@Override
public Map<Class<? extends Annotation>, ? extends Annotation> getUsageMap() {
if ( usageMap == null ) {
usageMap = AnnotationUsageBuilder.collectUsages( getAnnotationSource(), modelContext );
}
return usageMap;
}

@Override
public void clearAnnotationUsages() {
getUsageMap().clear();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.bytebuddy.internal;

import java.lang.annotation.Annotation;

import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext;
import org.hibernate.models.internal.StandardAnnotationDescriptor;
import org.hibernate.models.spi.AnnotationDescriptor;
import org.hibernate.models.spi.SourceModelBuildingContext;

import net.bytebuddy.description.annotation.AnnotationDescription;

/**
* @author Steve Ebersole
*/
public class AnnotationDescriptorImpl<A extends Annotation> extends StandardAnnotationDescriptor<A> {
public AnnotationDescriptorImpl(
Class<A> annotationType,
SourceModelBuildingContext buildingContext) {
super( annotationType, buildingContext );
}

public AnnotationDescriptorImpl(
Class<A> annotationType,
AnnotationDescriptor<?> repeatableContainer,
SourceModelBuildingContext buildingContext) {
super( annotationType, repeatableContainer, buildingContext );
}

public A createUsage(AnnotationDescription annotationDescription, ByteBuddyModelsContext context) {
return AnnotationUsageBuilder.makeUsage( annotationDescription, this, context );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.bytebuddy.internal;

import java.lang.annotation.Annotation;
import java.util.Map;

import org.hibernate.models.internal.AnnotationDescriptorRegistryStandard;
import org.hibernate.models.spi.AnnotationDescriptor;
import org.hibernate.models.spi.SourceModelBuildingContext;

/**
* @author Steve Ebersole
*/
public class AnnotationDescriptorRegistryImpl extends AnnotationDescriptorRegistryStandard {
public AnnotationDescriptorRegistryImpl(SourceModelBuildingContext modelBuildingContext) {
super( modelBuildingContext );
}

@Override
protected <A extends Annotation> AnnotationDescriptor<A> buildAnnotationDescriptor(
Class<A> javaType,
AnnotationDescriptor<? extends Annotation> containerDescriptor) {
return new AnnotationDescriptorImpl<>( javaType, containerDescriptor, getModelBuildingContext() );
}

public Map<Class<? extends Annotation>, AnnotationDescriptor<? extends Annotation>> getDescriptorMap() {
return descriptorMap;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.models.bytebuddy.internal;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;

import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext;
import org.hibernate.models.bytebuddy.spi.ValueExtractor;
import org.hibernate.models.internal.util.CollectionHelper;
import org.hibernate.models.spi.AnnotationDescriptor;
import org.hibernate.models.spi.AnnotationDescriptorRegistry;
import org.hibernate.models.spi.AttributeDescriptor;
import org.hibernate.models.spi.SourceModelBuildingContext;

import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.annotation.AnnotationSource;

/**
* Helper for building annotation usages/instances based on
* Jandex {@linkplain AnnotationDescription} references
*
* @author Steve Ebersole
*/
public class AnnotationUsageBuilder {
public static <A extends Annotation> A makeUsage(
AnnotationDescription annotationDescription,
AnnotationDescriptor<A> annotationDescriptor,
SourceModelBuildingContext modelContext) {
final Map<String, Object> attributeValues = extractAttributeValues(
annotationDescription,
annotationDescriptor,
modelContext
);
return annotationDescriptor.createUsage( attributeValues, modelContext );
}

private static <A extends Annotation> Map<String, Object> extractAttributeValues(
AnnotationDescription annotationDescription,
AnnotationDescriptor<A> annotationDescriptor,
SourceModelBuildingContext modelContext) {

if ( CollectionHelper.isEmpty( annotationDescriptor.getAttributes() ) ) {
return Collections.emptyMap();
}

final ConcurrentHashMap<String, Object> valueMap = new ConcurrentHashMap<>();
for ( int i = 0; i < annotationDescriptor.getAttributes().size(); i++ ) {
final AttributeDescriptor<?> attributeDescriptor = annotationDescriptor.getAttributes().get( i );
final ValueExtractor<?> extractor = modelContext
.as( ByteBuddyModelContextImpl.class )
.getValueExtractor( attributeDescriptor.getTypeDescriptor() );
final Object attributeValue = extractor.extractValue(
annotationDescription,
attributeDescriptor.getName(),
modelContext
);
valueMap.put( attributeDescriptor.getName(), attributeValue );
}
return valueMap;
}

public static Map<Class<? extends Annotation>, ? extends Annotation> collectUsages(
AnnotationSource annotationSource,
ByteBuddyModelsContext modelContext) {
if ( annotationSource == null ) {
return Collections.emptyMap();
}
final Map<Class<? extends Annotation>, Annotation> result = new HashMap<>();
processAnnotations(
annotationSource.getDeclaredAnnotations(),
result::put,
modelContext
);
return result;
}

/**
* Process annotations creating usage instances passed back to the consumer
*/
public static void processAnnotations(
AnnotationList annotations,
BiConsumer<Class<? extends Annotation>, Annotation> consumer,
ByteBuddyModelsContext buildingContext) {
final AnnotationDescriptorRegistry annotationDescriptorRegistry = buildingContext.getAnnotationDescriptorRegistry();

for ( AnnotationDescription annotation : annotations ) {
if ( annotation.getAnnotationType().represents( Documented.class )
|| annotation.getAnnotationType().represents( Repeatable.class )
|| annotation.getAnnotationType().represents( Retention.class )
|| annotation.getAnnotationType().represents( Target.class ) ) {
continue;
}

final Class<? extends Annotation> annotationType = buildingContext
.getClassLoading()
.classForName( annotation.getAnnotationType().getTypeName() );
final AnnotationDescriptor<?> annotationDescriptor = annotationDescriptorRegistry.getDescriptor( annotationType );
final Annotation usage = makeUsage(
annotation,
annotationDescriptor,
buildingContext
);
consumer.accept( annotationType, usage );
}
}
}
Loading