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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
* Portions Copyright 2013-2026 Philip Helger + contributors
* Portions Copyright 2013-2025 Philip Helger + contributors
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -353,6 +353,7 @@ public AbstractJClass narrowAny ()
@NonNull
public JAnnotatedClass annotated (@NonNull final Class <? extends Annotation> aClazz)
{
ValueEnforcer.notNull (aClazz, "Clazz");
return annotated (owner ().ref (aClazz));
}

Expand Down Expand Up @@ -392,9 +393,35 @@ public JAnnotatedClass annotated (@NonNull final Class <? extends Annotation> aC
@NonNull
public JAnnotatedClass annotated (@NonNull final AbstractJClass aClazz)
{
ValueEnforcer.notNull (aClazz, "Clazz");
return new JAnnotatedClass (this, new JAnnotationUse (aClazz));
}

/**
* Creates a new type with a type-use annotation (JSR 308, Java 8+).
* <p>
* This overload accepts a pre-configured {@link JAnnotationUse}, allowing annotations
* with parameters:
* <pre>
* JAnnotationUse sizeAnnotation = new JAnnotationUse(codeModel.ref(Size.class));
* sizeAnnotation.param("min", 1).param("max", 10);
* AbstractJClass annotatedString = stringClass.annotated(sizeAnnotation);
* // Generates: @Size(min = 1, max = 10) String
* </pre>
*
* @param aAnnotation
* The pre-configured annotation to apply as a type-use annotation.
* @return A new {@link JAnnotatedClass} wrapping this class with the annotation.
* @since 4.2.0
* @see #annotated(Class) for simple annotations without parameters
*/
@NonNull
public JAnnotatedClass annotated (@NonNull final JAnnotationUse aAnnotation)
{
ValueEnforcer.notNull (aAnnotation, "Annotation");
return new JAnnotatedClass (this, aAnnotation);
}

/**
* @return If this class is parameterized, the type parameters of the given index.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,18 @@
* Example: {@code private List<@NotNull String> items;}</li>
* </ul>
* <p>
* Use {@link AbstractJClass#annotated(Class)} or {@link AbstractJClass#annotated(AbstractJClass)}
* to create instances of this class.
* <b>Annotations with parameters:</b>
* <p>
* For annotations that require parameters, use {@link AbstractJClass#annotated(JAnnotationUse)}:
* <pre>
* JAnnotationUse sizeAnnotation = new JAnnotationUse(codeModel.ref(Size.class));
* sizeAnnotation.param("min", 1).param("max", 10);
* AbstractJClass annotatedString = stringClass.annotated(sizeAnnotation);
* // Generates: @Size(min = 1, max = 10) String
* </pre>
* <p>
* Use {@link AbstractJClass#annotated(Class)}, {@link AbstractJClass#annotated(AbstractJClass)},
* or {@link AbstractJClass#annotated(JAnnotationUse)} to create instances of this class.
*
* @since 4.2.0
*/
Expand Down Expand Up @@ -150,6 +160,15 @@ public JAnnotatedClass annotated (@NonNull final AbstractJClass aClazz)
return new JAnnotatedClass (m_aBasis, newAnnotations);
}

@Override
@NonNull
public JAnnotatedClass annotated (@NonNull final JAnnotationUse aAnnotation)
{
final List <JAnnotationUse> newAnnotations = new ArrayList <> (m_aAnnotations);
newAnnotations.add (aAnnotation);
return new JAnnotatedClass (m_aBasis, newAnnotations);
}

@Override
public String name ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,57 @@ public void testAnnotatedPrimitiveArrayType () throws JCodeModelException
testClass.field (JMod.PRIVATE, annotatedIntArray, "values");
CodeModelTestsHelper.parseCodeModel (cm);
}

/**
* Test annotation with parameters: {@code @SuppressWarnings("unchecked") String}
*/
@Test
public void testAnnotationWithParameters () throws JCodeModelException
{
final JCodeModel cm = JCodeModel.createUnified ();

// Create @SuppressWarnings("unchecked") String
final JAnnotationUse annotation = new JAnnotationUse (cm.ref (SuppressWarnings.class));
annotation.param ("value", "unchecked");
final AbstractJClass stringClass = cm.ref (String.class);
final JAnnotatedClass annotatedString = stringClass.annotated (annotation);

// Check generated output
final String generated = CodeModelTestsHelper.generate (annotatedString);
assertEquals ("@java.lang.SuppressWarnings(\"unchecked\") java.lang.String", generated);

// Verify it parses when used in a class
final JDefinedClass testClass = cm._class ("com.example.Test");
testClass.field (JMod.PRIVATE, annotatedString, "value");
CodeModelTestsHelper.parseCodeModel (cm);
}

/**
* Test annotation with multiple parameters in a generic type.
*/
@Test
public void testAnnotationWithMultipleParameters () throws JCodeModelException
{
final JCodeModel cm = JCodeModel.createUnified ();
final JDefinedClass testClass = cm._class ("com.example.Test");

// Create a custom annotation class for testing (simulating @Size(min=1, max=10))
// We'll use @SuppressWarnings with array param as a proxy since it's available
final JAnnotationUse annotation = new JAnnotationUse (cm.ref (SuppressWarnings.class));
annotation.paramArray ("value", "unchecked", "rawtypes");

final AbstractJClass stringClass = cm.ref (String.class);
final JAnnotatedClass annotatedString = stringClass.annotated (annotation);
final AbstractJClass listType = cm.ref (List.class).narrow (annotatedString);

testClass.field (JMod.PRIVATE, listType, "items");

// Check the generated output contains the annotation with parameters
final String classOutput = CodeModelTestsHelper.declare (testClass);
assertTrue ("Expected annotation with array parameters in output",
classOutput.contains ("@java.lang.SuppressWarnings({"));

// Verify it parses
CodeModelTestsHelper.parseCodeModel (cm);
}
}