Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/nightly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-22.04, windows-2022 ]
moduleSet: [ core, it, jpa, jpa-oracle, dbclient, dbclient-oracle, others ]
moduleSet: [ core, it, jpa, jpa-oracle, dbclient, dbclient-oracle, others, data, data-oracle ]
include:
- { os: ubuntu-22.04, platform: linux }
- { os: windows-2022, platform: windows }
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-22.04, windows-2022 ]
moduleSet: [ core, it, jpa, jpa-oracle, dbclient, dbclient-oracle, others ]
moduleSet: [ core, it, jpa, jpa-oracle, dbclient, dbclient-oracle, others, data, data-oracle ]
include:
- { os: ubuntu-22.04, platform: linux }
- { os: windows-2022, platform: windows }
Expand Down
10 changes: 10 additions & 0 deletions .mvn/cache-config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@
<include>tests/integration/jpa/**</include>
</includes>
</moduleSet>
<moduleSet name="data-oracle">
<includes>
<include>data/tests/**/ucp/**</include>
</includes>
</moduleSet>
<moduleSet name="data">
<includes>
<include>data/tests/**</include>
</includes>
</moduleSet>
<moduleSet name="dbclient-oracle">
<includes>
<include>tests/integration/dbclient/oracle/**</include>
Expand Down
8 changes: 8 additions & 0 deletions all/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,14 @@
<groupId>io.helidon.json.schema</groupId>
<artifactId>helidon-json-schema-codegen</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.validation</groupId>
<artifactId>helidon-validation</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-validation</artifactId>
</dependency>
</dependencies>

</project>
11 changes: 11 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,17 @@
<version>${helidon.version}</version>
</dependency>


<dependency>
<groupId>io.helidon.validation</groupId>
<artifactId>helidon-validation</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-validation</artifactId>
<version>${helidon.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
* Copyright (c) 2023, 2025 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,7 @@ public interface Annotated {
* @return the list of annotations declared on this element
*/
@Option.Singular
@Option.Redundant
List<Annotation> annotations();

/**
Expand All @@ -49,6 +50,7 @@ public interface Annotated {
* @return list of all meta annotations of this element
*/
@Option.Singular
@Option.Redundant
List<Annotation> inheritedAnnotations();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
@Prototype.Blueprint(decorator = TypeNameSupport.Decorator.class)
@Prototype.CustomMethods(TypeNameSupport.class)
@Prototype.Implement("java.lang.Comparable<TypeName>")
interface TypeNameBlueprint {
interface TypeNameBlueprint extends Annotated {
/**
* Functions similar to {@link Class#getPackageName()}.
*
Expand Down
151 changes: 93 additions & 58 deletions codegen/apt/src/main/java/io/helidon/codegen/apt/AptTypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
Expand All @@ -42,6 +43,7 @@
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;

import io.helidon.common.types.TypeName;
import io.helidon.common.types.TypeNames;
Expand All @@ -56,6 +58,7 @@
@Deprecated(forRemoval = true, since = "4.2.0")
public final class AptTypeFactory {
private static final Pattern NESTED_TYPES = Pattern.compile("(?<!\\$)\\$(?!\\$)");

private AptTypeFactory() {
}

Expand All @@ -75,13 +78,67 @@ public static Optional<TypeName> createTypeName(DeclaredType type) {
* @param typeMirror annotation processing type mirror
* @return type name
* @throws IllegalArgumentException when the mirror cannot be resolved into a name (such as when it represents
* none or error)
* none or error)
*/
public static Optional<TypeName> createTypeName(TypeMirror typeMirror) {
return createTypeName(new HashSet<>(), typeMirror);
return createTypeName(null, new HashSet<>(), typeMirror);
}

/**
* Create type from type mirror. The element is needed to correctly map
* type arguments to type parameters.
*
* @param element the type element of the type mirror
* @param mirror the type mirror as declared in source code
* @return type for the provided values
*/
public static Optional<TypeName> createTypeName(TypeElement element, TypeMirror mirror) {
Optional<TypeName> result = createTypeName(null, new HashSet<>(), mirror);
if (result.isEmpty()) {
return result;
}

TypeName mirrorName = result.get();
int typeArgumentSize = mirrorName.typeArguments().size();

List<String> typeParameters = element.getTypeParameters()
.stream()
.map(TypeParameterElement::toString)
.toList();
if (typeArgumentSize > typeParameters.size()) {
throw new IllegalStateException("Found " + typeArgumentSize + " type arguments, but only " + typeParameters.size()
+ " type parameters on: " + mirror);
}
return Optional.of(TypeName.builder(mirrorName)
.typeParameters(typeParameters)
.build());
}

/**
* Creates a name from an element type during annotation processing.
*
* @param type the element type
* @return the associated type name instance
*/
public static Optional<TypeName> createTypeName(Element type) {
return createTypeName(null, new HashSet<>(), type);
}

/**
* A replacement for {@link #createTypeName(javax.lang.model.element.Element)}, as we require elements to be able
* to process annotations.
*
* @param elements APT elements
* @param type element to get type name for
* @return type name, if available, may include type argument annotations (i.e. {@code List<@NonEmpty String>}}
*/
static Optional<TypeName> createTypeName(Elements elements, Element type) {
return createTypeName(elements, new HashSet<>(), type);
}

private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, TypeMirror typeMirror) {
// we must accept `null` elements, until we hide the methods from public
// as otherwise this whole method would have to be duplicated
private static Optional<TypeName> createTypeName(Elements elements, Set<TypeMirror> inProgress, TypeMirror typeMirror) {
TypeKind kind = typeMirror.getKind();
if (kind.isPrimitive()) {
Class<?> type = switch (kind) {
Expand Down Expand Up @@ -112,8 +169,8 @@ private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, Typ
var builder = TypeName.builder(createFromGenericDeclaration(typeMirror.toString()));

var typeVar = ((TypeVariable) typeMirror);
handleBounds(inProgress, typeVar.getUpperBound(), builder::addUpperBound);
handleBounds(inProgress, typeVar.getLowerBound(), builder::addLowerBound);
handleBounds(elements, inProgress, typeVar.getUpperBound(), builder::addUpperBound);
handleBounds(elements, inProgress, typeVar.getLowerBound(), builder::addLowerBound);

return Optional.of(builder.build());
} finally {
Expand All @@ -127,8 +184,8 @@ private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, Typ
.wildcard(true)
.className("?");

handleBounds(inProgress, vt.getExtendsBound(), builder::addUpperBound);
handleBounds(inProgress, vt.getSuperBound(), builder::addLowerBound);
handleBounds(elements, inProgress, vt.getExtendsBound(), builder::addUpperBound);
handleBounds(elements, inProgress, vt.getSuperBound(), builder::addLowerBound);

return Optional.of(builder.build());
}
Expand All @@ -145,7 +202,7 @@ private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, Typ
}

if (typeMirror instanceof ArrayType arrayType) {
TypeName typeName = createTypeName(inProgress, arrayType.getComponentType()).orElseThrow();
TypeName typeName = createTypeName(elements, inProgress, arrayType.getComponentType()).orElseThrow();
return Optional.of(TypeName.builder(typeName)
.componentType(typeName)
.array(true)
Expand All @@ -155,12 +212,27 @@ private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, Typ
if (typeMirror instanceof DeclaredType declaredType) {
List<TypeName> typeParams = declaredType.getTypeArguments()
.stream()
.map(it -> createTypeName(inProgress, it))
.map(it -> createTypeName(elements, inProgress, it))
.flatMap(Optional::stream)
.collect(Collectors.toList());

TypeName result = createTypeName(inProgress, declaredType.asElement()).orElse(null);
if (typeParams.isEmpty() || result == null) {
TypeName result = createTypeName(elements, inProgress, declaredType.asElement()).orElse(null);

if (result == null) {
return Optional.empty();
}

var annotationMirrors = declaredType.getAnnotationMirrors();
if (!annotationMirrors.isEmpty() && elements != null) {
// we cannot do this if elements is null
var newResultBuilder = TypeName.builder(result);
for (AnnotationMirror annotationMirror : annotationMirrors) {
newResultBuilder.addAnnotation(AptAnnotationFactory.createAnnotation(annotationMirror, elements));
}
result = newResultBuilder.build();
}

if (typeParams.isEmpty()) {
return Optional.ofNullable(result);
}

Expand All @@ -173,7 +245,10 @@ private static Optional<TypeName> createTypeName(Set<TypeMirror> inProgress, Typ
throw new IllegalStateException("Unknown type mirror: " + typeMirror);
}

private static void handleBounds(Set<TypeMirror> processed, TypeMirror boundMirror, Consumer<TypeName> boundHandler) {
private static void handleBounds(Elements elements,
Set<TypeMirror> processed,
TypeMirror boundMirror,
Consumer<TypeName> boundHandler) {
if (boundMirror == null) {
return;
}
Expand All @@ -183,71 +258,31 @@ private static void handleBounds(Set<TypeMirror> processed, TypeMirror boundMirr
it.getBounds()
.stream()
.filter(Predicate.not(processed::equals))
.map(typeMirror -> createTypeName(processed, typeMirror))
.map(typeMirror -> createTypeName(elements, processed, typeMirror))
.flatMap(Optional::stream)
.filter(Predicate.not(TypeNames.OBJECT::equals))
.forEach(boundHandler);

} else {
createTypeName(processed, boundMirror)
createTypeName(elements, processed, boundMirror)
.filter(Predicate.not(TypeNames.OBJECT::equals))
.ifPresent(boundHandler);
}
}
}

/**
* Create type from type mirror. The element is needed to correctly map
* type arguments to type parameters.
*
* @param element the type element of the type mirror
* @param mirror the type mirror as declared in source code
* @return type for the provided values
*/
public static Optional<TypeName> createTypeName(TypeElement element, TypeMirror mirror) {
Optional<TypeName> result = createTypeName(new HashSet<>(), mirror);
if (result.isEmpty()) {
return result;
}

TypeName mirrorName = result.get();
int typeArgumentSize = mirrorName.typeArguments().size();

List<String> typeParameters = element.getTypeParameters()
.stream()
.map(TypeParameterElement::toString)
.toList();
if (typeArgumentSize > typeParameters.size()) {
throw new IllegalStateException("Found " + typeArgumentSize + " type arguments, but only " + typeParameters.size()
+ " type parameters on: " + mirror);
}
return Optional.of(TypeName.builder(mirrorName)
.typeParameters(typeParameters)
.build());
}

/**
* Creates a name from an element type during annotation processing.
*
* @param type the element type
* @return the associated type name instance
*/
public static Optional<TypeName> createTypeName(Element type) {
return createTypeName(new HashSet<>(), type);
}

private static Optional<TypeName> createTypeName(Set<TypeMirror> processed, Element type) {
private static Optional<TypeName> createTypeName(Elements elements, Set<TypeMirror> processed, Element type) {
if (type instanceof VariableElement) {
return createTypeName(processed, type.asType());
return createTypeName(elements, processed, type.asType());
}

if (type instanceof ExecutableElement ee) {
return createTypeName(processed, ee.getReturnType());
return createTypeName(elements, processed, ee.getReturnType());
}

if (type.getKind() == ElementKind.TYPE_PARAMETER) {
TypeMirror mirror = type.asType();
return createTypeName(processed, mirror);
return createTypeName(elements, processed, mirror);
}

List<String> classNames = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public static Optional<TypedElementInfo> createTypedElementInfoFromElement(AptCo
Element v,
Elements elements,
boolean varargType) {
TypeName type = AptTypeFactory.createTypeName(v).orElse(null);
TypeName type = AptTypeFactory.createTypeName(elements, v).orElse(null);
TypeMirror typeMirror = null;
String defaultValue = null;
List<TypedElementInfo> params = List.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ default T addContentLine(String line) {
return addContent(line).addContent("\n");
}

/**
* Add a new line (empty).
*
* @return updated builder instance
*/
default T addContentLine() {
return addContent("\n");
}

/**
* Adds the provided literal as content, enclosed in double quotes.
*
Expand Down
Loading