Skip to content

Commit

Permalink
Merge branch 'release/1.0.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
vegegoku committed Nov 6, 2024
2 parents 014cacf + 4479071 commit 91edab0
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
java-version: [ 11 ]
java-version: [ 11, 17, 21, 23 ]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions domino-jackson-processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.dominokit</groupId>
<artifactId>domino-jackson-parent</artifactId>
<version>1.0.4</version>
<version>1.0.5</version>
</parent>

<artifactId>domino-jackson-processor</artifactId>
Expand Down Expand Up @@ -108,7 +108,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.jackson.records;

import org.dominokit.jackson.annotation.JSONMapper;

@JSONMapper
public record Circle(double radius) {
public static final double PI = 3.14159;

public Circle {
if (radius < 0) {
throw new IllegalArgumentException("Radius cannot be negative");
}
}

public double area() {
return PI * radius * radius;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.jackson.records;

import org.dominokit.jackson.annotation.JSONMapper;

@JSONMapper
public record ComplexNumber(double real, double imaginary) {
public ComplexNumber(double real) {
this(real, 0); // Calls the canonical constructor with 0 for the imaginary part
}

public double magnitude() {
return Math.sqrt(real * real + imaginary * imaginary);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.jackson.records;

import org.dominokit.jackson.annotation.JSONMapper;

@JSONMapper
public record Point(int x, int y) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.jackson.records;

import org.junit.Assert;
import org.junit.Test;

public class RecordIT {

private static final Point_MapperImpl POINT_MAPPER = new Point_MapperImpl();
private static final Circle_MapperImpl CIRCLE_MAPPER = new Circle_MapperImpl();
private static final ComplexNumber_MapperImpl COMPLEX_NUMBER_MAPPER = new ComplexNumber_MapperImpl();
private static final Rectangle_MapperImpl RECTANGLE_MAPPER = new Rectangle_MapperImpl();

@Test
public void simpleRecordTest(){
String pointJson = POINT_MAPPER.write(new Point(10, 20));
Point point = POINT_MAPPER.read(pointJson);

Assert.assertEquals("{\"x\":10,\"y\":20}", pointJson);
Assert.assertEquals(10, point.x());
Assert.assertEquals(20, point.y());
Assert.assertEquals(new Point(10, 20), point);

String circleJson = CIRCLE_MAPPER.write(new Circle(10.0));
Circle circle = CIRCLE_MAPPER.read(circleJson);

Assert.assertEquals("{\"radius\":10.0}", circleJson);
Assert.assertEquals(10.0, circle.radius(), 0.001);
Assert.assertEquals(new Circle(10), circle);

String complexNumberJson = COMPLEX_NUMBER_MAPPER.write(new ComplexNumber(10.0));
ComplexNumber complexNumber = COMPLEX_NUMBER_MAPPER.read(complexNumberJson);

Assert.assertEquals("{\"real\":10.0,\"imaginary\":0.0}", complexNumberJson);
Assert.assertEquals(10.0, complexNumber.real(), 0.001);
Assert.assertEquals(0, complexNumber.imaginary(), 0.001);
Assert.assertEquals(new ComplexNumber(10.0), complexNumber);

String rectangleJson = RECTANGLE_MAPPER.write(new Rectangle(new Point(10,20), new Point(20, 30)));
Rectangle rectangle = RECTANGLE_MAPPER.read(rectangleJson);

Assert.assertEquals("{\"bottomLeft\":{\"x\":10,\"y\":20},\"topRight\":{\"x\":20,\"y\":30}}", rectangleJson);
Assert.assertEquals(new Point(10, 20), rectangle.a());
Assert.assertEquals(new Point(20, 30), rectangle.b());
Assert.assertEquals(new Rectangle(new Point(10,20), new Point(20, 30)), rectangle);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright © 2019 Dominokit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dominokit.jackson.records;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.dominokit.jackson.annotation.JSONMapper;

@JSONMapper
public record Rectangle(@JsonProperty("bottomLeft") Point a, @JsonProperty("topRight") Point b) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -970,4 +970,14 @@ private static TypeElement toTypeElement(TypeMirror type) {
public static String getTypeQualifiedName(TypeMirror typeMirror) {
return ((TypeElement) typeUtils.asElement(typeMirror)).getQualifiedName().toString();
}

public static boolean isRecord(TypeMirror type) {
boolean result = false;
TypeElement recordElement = elementUtils.getTypeElement("java.lang.Record");
if (recordElement != null) { // If running on Java 16+
TypeMirror recordType = recordElement.asType();
result = typeUtils.isSubtype(type, recordType);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,51 @@
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.*;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.WildcardTypeName;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.Filer;
import javax.lang.model.element.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import org.dominokit.jackson.JacksonContextProvider;
import org.dominokit.jackson.JsonDeserializationContext;
import org.dominokit.jackson.JsonDeserializer;
import org.dominokit.jackson.JsonDeserializerParameters;
import org.dominokit.jackson.deser.bean.*;
import org.dominokit.jackson.deser.bean.AbstractBeanJsonDeserializer;
import org.dominokit.jackson.deser.bean.AbstractIdentityDeserializationInfo;
import org.dominokit.jackson.deser.bean.BeanPropertyDeserializer;
import org.dominokit.jackson.deser.bean.HasDeserializerAndParameters;
import org.dominokit.jackson.deser.bean.IdentityDeserializationInfo;
import org.dominokit.jackson.deser.bean.Instance;
import org.dominokit.jackson.deser.bean.InstanceBuilder;
import org.dominokit.jackson.deser.bean.MapLike;
import org.dominokit.jackson.deser.bean.PropertyIdentityDeserializationInfo;
import org.dominokit.jackson.deser.bean.SubtypeDeserializer;
import org.dominokit.jackson.deser.bean.SubtypeDeserializer.BeanSubtypeDeserializer;
import org.dominokit.jackson.deser.bean.TypeDeserializationInfo;
import org.dominokit.jackson.exception.JsonDeserializationException;
import org.dominokit.jackson.processor.AbstractJsonMapperGenerator;
import org.dominokit.jackson.processor.AbstractMapperProcessor;
Expand Down Expand Up @@ -167,7 +196,7 @@ protected Set<MethodSpec> moreMethods() {
// Object instance can be created by InstanceBuilder
// only for non-abstract classes
if (beanType.getKind() == TypeKind.DECLARED
&& ((DeclaredType) beanType).asElement().getKind() == ElementKind.CLASS
&& (((DeclaredType) beanType).asElement().getKind() == ElementKind.CLASS || isRecord())
&& !((DeclaredType) beanType).asElement().getModifiers().contains(Modifier.ABSTRACT)) {
methods.add(buildInitInstanceBuilderMethod());
}
Expand Down Expand Up @@ -261,6 +290,10 @@ private boolean isUseJsonCreator() {
.anyMatch(o -> o.getAnnotation(JsonCreator.class) != null);
}

private boolean isRecord() {
return Type.isRecord(beanType);
}

private ExecutableElement getCreator() {
return ((DeclaredType) beanType)
.asElement().getEnclosedElements().stream()
Expand All @@ -270,6 +303,40 @@ private ExecutableElement getCreator() {
.orElse(null);
}

public Optional<ExecutableElement> getRecordCanonicalConstructor() {
TypeElement typeElement = (TypeElement) typeUtils.asElement(beanType);
// Get all fields declared in the class itself (assuming these are the record components)
List<VariableElement> recordFields =
ElementFilter.fieldsIn(typeElement.getEnclosedElements()).stream()
.filter(
field ->
field.getModifiers().contains(Modifier.FINAL)
&& !field.getModifiers().contains(Modifier.STATIC))
.collect(Collectors.toList());

// Find a constructor whose parameters match the record fields
for (ExecutableElement constructor :
ElementFilter.constructorsIn(typeElement.getEnclosedElements())) {
List<? extends VariableElement> parameters = constructor.getParameters();

if (parameters.size() == recordFields.size()) {
boolean matches = true;

// Check if parameter types match field types in order
for (int i = 0; i < parameters.size(); i++) {
if (!typeUtils.isSameType(parameters.get(i).asType(), recordFields.get(i).asType())) {
matches = false;
break;
}
}
if (matches) {
return Optional.of(constructor); // Canonical constructor found
}
}
}
return Optional.empty(); // Canonical constructor not found
}

private boolean isUseBuilder() {
String builderName = getBuilderName();
return builderName != null && !builderName.isEmpty();
Expand Down Expand Up @@ -359,8 +426,16 @@ private MethodSpec buildInitInstanceBuilderMethod() {
ParameterizedTypeName.get(
ClassName.get(InstanceBuilder.class), ClassName.get(beanType)));

if (isUseJsonCreator()) {
ExecutableElement creator = getCreator();
boolean jsonCreator = isUseJsonCreator();
boolean record = isRecord();

if (jsonCreator || record) {
ExecutableElement creator;
if (jsonCreator) {
creator = getCreator();
} else {
creator = getRecordCanonicalConstructor().get();
}
List<? extends VariableElement> parameterTypes = creator.getParameters();
parameterBuilders =
parameterTypes.stream()
Expand Down Expand Up @@ -424,7 +499,7 @@ private TypeSpec instanceBuilderReturnType(boolean useBuilder) {
.addModifiers(Modifier.PRIVATE)
.returns(ClassName.get(beanType));

if (isUseJsonCreator()) {
if (isUseJsonCreator() || isRecord()) {
for (ParameterDeserializerBuilder parameterBuilder : parameterBuilders) {
createMethodBuilder.addParameter(
Type.wrapperType(parameterBuilder.getParameterType()),
Expand Down Expand Up @@ -493,7 +568,7 @@ private MethodSpec newInstanceMethod(
+ buildMethodName
+ "(), bufferedProperties)",
ParameterizedTypeName.get(ClassName.get(Instance.class), ClassName.get(beanType)));
} else if (isUseJsonCreator()) {
} else if (isUseJsonCreator() || isRecord()) {
buildAssignProperties(beanType, createMethod, builder);
} else {
builder.addStatement(
Expand Down Expand Up @@ -549,7 +624,7 @@ private MethodSpec getDeserializerMethod() {
}

private Optional<MethodSpec> buildInitDeserializersMethod(TypeMirror beanType) {
if (isUseBuilder() || isUseJsonCreator() || isAbstract(beanType)) {
if (isUseBuilder() || isUseJsonCreator() || isAbstract(beanType) || isRecord()) {
return Optional.empty();
}
TypeName resultType =
Expand Down
Loading

0 comments on commit 91edab0

Please sign in to comment.