Skip to content

Commit fd67294

Browse files
authored
Merge pull request #344 from domaframework/support-record
Support records
2 parents 93e0358 + c781315 commit fd67294

File tree

11 files changed

+101
-9
lines changed

11 files changed

+101
-9
lines changed

docs/domain.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ The value ``new`` means that the object of annotated class is created with a con
4545
}
4646
}
4747
48+
.. note::
49+
In Java 14 and later version, you can annotate `records`_ with ``@Domain``:
50+
51+
.. code-block:: java
52+
53+
@Domain(valueType = String.class, accessorMethod = "value")
54+
public record PhoneNumber(String value) {
55+
public String getAreaCode() {
56+
...
57+
}
58+
}
59+
60+
.. _records: https://openjdk.java.net/jeps/359
61+
62+
4863
Instantiation with a static factory method
4964
------------------------------------------
5065

docs/embeddable.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ The above entity definition is equivalent to following one:
6060
String zip;
6161
}
6262
63+
.. note::
64+
In Java 14 and later version, you can annotate `records`_ with ``@Embeddable``:
65+
66+
.. code-block:: java
67+
68+
@Embeddable
69+
public record Address(
70+
String city,
71+
String street,
72+
@Column(name = "ZIP_CODE")String zip) {
73+
}
74+
75+
.. _records: https://openjdk.java.net/jeps/359
6376

6477
Naming convention
6578
-----------------

docs/entity.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ The following code snippet shows how to inherit other entity class:
3030
...
3131
}
3232
33+
.. note::
34+
In Java 14 and later version, you can annotate `records`_ with ``@Entity``:
35+
36+
.. code-block:: java
37+
38+
@Entity
39+
public record Employee(...) {
40+
}
41+
42+
In the case, the entity is recognize as :ref:`immutable`
43+
even though the immutable property of ``@Entity`` is ``false``.
44+
45+
.. _records: https://openjdk.java.net/jeps/359
3346

3447
Entity listeners
3548
---------------------------
@@ -77,6 +90,8 @@ the naming convention is ignored.
7790

7891
An entity subclass inherits parent's naming convention.
7992

93+
.. _immutable:
94+
8095
Immutable
8196
----------------------------
8297

src/main/java/org/seasar/doma/Entity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@
105105
* <p>If not specified and the entity class inherits another entity class, this value is inherited
106106
* from the parent entity class. The values must be consistent in the hierarchy.
107107
*
108+
* <p>If not specified and the entity class is a record, the class is recognized as immutable even
109+
* though this value is {@code false}.
110+
*
108111
* @return whether the entity class is immutable
109112
*/
110113
boolean immutable() default false;

src/main/java/org/seasar/doma/internal/apt/cttype/CtTypes.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.seasar.doma.internal.apt.AptIllegalStateException;
5353
import org.seasar.doma.internal.apt.Context;
5454
import org.seasar.doma.internal.apt.annot.DomainConvertersAnnot;
55+
import org.seasar.doma.internal.apt.util.ElementKindUtil;
5556
import org.seasar.doma.jdbc.BatchResult;
5657
import org.seasar.doma.jdbc.Config;
5758
import org.seasar.doma.jdbc.PreparedSql;
@@ -347,7 +348,8 @@ private EntityCtType newEntityCtType(TypeMirror type) {
347348
}
348349
Name binaryName = ctx.getMoreElements().getBinaryName(typeElement);
349350
ClassName descClassName = ClassNames.newEntityDescClassName(binaryName);
350-
return new EntityCtType(ctx, type, entity.immutable(), descClassName);
351+
boolean immutable = ElementKindUtil.isRecord(typeElement.getKind()) || entity.immutable();
352+
return new EntityCtType(ctx, type, immutable, descClassName);
351353
}
352354

353355
private FunctionCtType newFunctionCtType(TypeMirror type) {

src/main/java/org/seasar/doma/internal/apt/meta/domain/DomainMetaFactory.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.seasar.doma.internal.apt.cttype.BasicCtType;
3030
import org.seasar.doma.internal.apt.def.TypeParametersDef;
3131
import org.seasar.doma.internal.apt.meta.TypeElementMetaFactory;
32+
import org.seasar.doma.internal.apt.util.ElementKindUtil;
3233
import org.seasar.doma.internal.util.StringUtil;
3334
import org.seasar.doma.message.Message;
3435

@@ -129,15 +130,16 @@ public void validateAcceptNull(TypeElement classElement, DomainMeta domainMeta)
129130

130131
@Override
131132
public void validateClass(TypeElement classElement, DomainMeta domainMeta) {
132-
if (classElement.getKind() == ElementKind.CLASS) {
133+
ElementKind kind = classElement.getKind();
134+
if (kind == ElementKind.CLASS || ElementKindUtil.isRecord(kind)) {
133135
if (domainMeta.providesConstructor()
134136
&& classElement.getModifiers().contains(Modifier.ABSTRACT)) {
135137
throw new AptException(Message.DOMA4132, classElement, new Object[] {});
136138
}
137139
if (classElement.getNestingKind().isNested()) {
138140
validateEnclosingElement(classElement);
139141
}
140-
} else if (classElement.getKind() == ElementKind.ENUM) {
142+
} else if (kind == ElementKind.ENUM) {
141143
if (domainMeta.providesConstructor()) {
142144
DomainAnnot domainAnnot = domainMeta.getDomainAnnot();
143145
throw new AptException(
@@ -150,7 +152,7 @@ public void validateClass(TypeElement classElement, DomainMeta domainMeta) {
150152
if (classElement.getNestingKind().isNested()) {
151153
validateEnclosingElement(classElement);
152154
}
153-
} else if (classElement.getKind() == ElementKind.INTERFACE) {
155+
} else if (kind == ElementKind.INTERFACE) {
154156
if (domainMeta.providesConstructor()) {
155157
throw new AptException(Message.DOMA4268, classElement, new Object[] {});
156158
}

src/main/java/org/seasar/doma/internal/apt/meta/entity/EmbeddableMetaFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.seasar.doma.internal.apt.annot.EmbeddableAnnot;
4141
import org.seasar.doma.internal.apt.annot.ValueAnnot;
4242
import org.seasar.doma.internal.apt.meta.TypeElementMetaFactory;
43+
import org.seasar.doma.internal.apt.util.ElementKindUtil;
4344
import org.seasar.doma.message.Message;
4445

4546
public class EmbeddableMetaFactory implements TypeElementMetaFactory<EmbeddableMeta> {
@@ -98,7 +99,8 @@ protected static class DefaultStrategy implements Strategy {
9899

99100
@Override
100101
public void validateClass(TypeElement embeddableElement, EmbeddableMeta embeddableMeta) {
101-
if (embeddableElement.getKind() != ElementKind.CLASS) {
102+
ElementKind kind = embeddableElement.getKind();
103+
if (kind != ElementKind.CLASS && !ElementKindUtil.isRecord(kind)) {
102104
EmbeddableAnnot embeddableAnnot = embeddableMeta.getEmbeddableAnnot();
103105
throw new AptException(
104106
Message.DOMA4283,

src/main/java/org/seasar/doma/internal/apt/meta/entity/EntityMetaFactory.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.seasar.doma.internal.apt.annot.ValueAnnot;
4242
import org.seasar.doma.internal.apt.meta.TypeElementMetaFactory;
4343
import org.seasar.doma.internal.apt.util.AnnotationValueUtil;
44+
import org.seasar.doma.internal.apt.util.ElementKindUtil;
4445
import org.seasar.doma.jdbc.entity.EntityListener;
4546
import org.seasar.doma.jdbc.entity.NamingType;
4647
import org.seasar.doma.jdbc.entity.NullEntityListener;
@@ -126,6 +127,9 @@ private NamingType resolveNamingType(TypeElement classElement) {
126127
}
127128

128129
private boolean resolveImmutable(TypeElement classElement, EntityAnnot entityAnnot) {
130+
if (ElementKindUtil.isRecord(classElement.getKind())) {
131+
return true;
132+
}
129133
boolean result = false;
130134
List<Boolean> resolvedList = new ArrayList<>();
131135
for (AnnotationValue value : getEntityElementValueList(classElement, "immutable")) {
@@ -205,7 +209,8 @@ public void doClassElement(TypeElement classElement, EntityMeta entityMeta) {
205209

206210
void validateClass(TypeElement classElement, EntityMeta entityMeta) {
207211
EntityAnnot entityAnnot = entityMeta.getEntityAnnot();
208-
if (classElement.getKind() != ElementKind.CLASS) {
212+
ElementKind kind = classElement.getKind();
213+
if (kind != ElementKind.CLASS && !ElementKindUtil.isRecord(kind)) {
209214
throw new AptException(
210215
Message.DOMA4015, classElement, entityAnnot.getAnnotationMirror(), new Object[] {});
211216
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.seasar.doma.internal.apt.util;
2+
3+
import java.util.Arrays;
4+
import javax.lang.model.element.ElementKind;
5+
6+
public final class ElementKindUtil {
7+
8+
private static final ElementKind RECORD =
9+
Arrays.stream(ElementKind.values())
10+
.filter(k -> "RECORD".equals(k.name()))
11+
.findAny()
12+
.orElse(null);
13+
14+
public static boolean isRecord(ElementKind kind) {
15+
if (RECORD == null) {
16+
return false;
17+
}
18+
return RECORD == kind;
19+
}
20+
}

src/main/java/org/seasar/doma/message/Message.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ public enum Message implements MessageResource {
376376
DOMA4011(
377377
"The annotation processing for the class \"{0}\" is failed. The cause is as follows: {1}"),
378378
DOMA4014("Cannot annotate the type with @Dao because the type isn''t an interface."),
379-
DOMA4015("Cannot annotate the type with @Entity because the type isn''t a class."),
379+
DOMA4015(
380+
"Cannot annotate the type with @Entity because the type is neither a class nor a record."),
380381
DOMA4016(
381382
"An unexpected error has occurred. It may be a bug in the Doma framework. Report the following stacktrace: {0}"),
382383
DOMA4017("The DAO interface must be a top level interface."),
@@ -464,7 +465,7 @@ public enum Message implements MessageResource {
464465
DOMA4104(
465466
"The accessor method \"{0}\" is not found. "
466467
+ "The method must have the return type \"{1}\" and must be non-private and non-args."),
467-
DOMA4105("You can annotate only classes, interfaces and enums with @Domain"),
468+
DOMA4105("You can annotate only classes, interfaces, enums and records with @Domain"),
468469
DOMA4106(
469470
"The factory method \"{0}\" is not found. "
470471
+ "The method must have the return type \"{1}\" and the parameter type \"{2}\" and must be non-private and static. "
@@ -803,7 +804,7 @@ public enum Message implements MessageResource {
803804
DOMA4281(
804805
"The number, type and name of the constructor parameters must correspond to "
805806
+ "those of persistent fields in the immutable entity class."),
806-
DOMA4283("You can annotated only classes with @Embeddable."),
807+
DOMA4283("You can annotate only classes and records with @Embeddable."),
807808
DOMA4285("The embeddable class must not have a type parameter."),
808809
DOMA4286("The fields of the embeddable class cannot be annotated with @OriginalStates."),
809810
DOMA4288("The annotation \"{0}\" competes with the annotation \"{1}\"."),

0 commit comments

Comments
 (0)