Skip to content

Commit

Permalink
Merge pull request #542 from eclipse/include-array-fields-supports
Browse files Browse the repository at this point in the history
Include support to Arrays fields
  • Loading branch information
otaviojava authored Aug 10, 2024
2 parents 2878b85 + b986141 commit f8db987
Show file tree
Hide file tree
Showing 36 changed files with 925 additions and 190 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version
- Include the `Null`, `NotNull` and `countAll` keywords in the method by query in the Repository
- Include condition to is NUll and is Not Null in the query
- Include pagination with Query annotation
- Add support to array in the fields

=== Fixed

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.metadata;

import java.util.Collection;

/**
* The ArrayFieldMetadata interface extends the {@link FieldMetadata} interface and provides
* additional information about a parameter with a generic type for arrays.
*
* <p>This interface is used to represent parameters of generic types, where the type is an array
* containing elements of a specific type.</p>
*
* @see FieldMetadata
*/
public interface ArrayFieldMetadata extends FieldMetadata {

/**
* Returns true if the array element type has either Entity or Embeddable annotations.
*
* @return true if the element type has Entity or Embeddable annotations
*/
boolean isEmbeddable();

/**
* Returns the {@link Class} representing the type of elements in the array.
*
* @return the element type of the array parameter
*/
Class<?> elementType();

/**
* Converts the provided {@link Collection} into an array of the appropriate type.
*
* @param collection the collection to be converted into an array
* @return an array containing the elements of the collection, as an Object
*/
Object arrayInstance(Collection<?> collection);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.metadata;

import java.util.Collection;

/**
* The ArrayParameterMetaData interface extends the {@link ParameterMetaData} interface and provides
* additional information about a parameter with a generic type for arrays.
*
* <p>This interface is used to represent parameters of generic types, where the type is an array
* containing elements of a specific type.</p>
*
* @see ParameterMetaData
*/
public interface ArrayParameterMetaData extends ParameterMetaData {

/**
* Returns the {@link Class} representing the type of elements in the array.
*
* @return the element type of the array parameter
*/
Class<?> elementType();

/**
* Converts the provided {@link Collection} into an array of the appropriate type.
*
* @param collection the collection to be converted into an array
* @return an array containing the elements of the collection, as an Object
*/
Object arrayInstance(Collection<?> collection);
}

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* enum that contains kinds of annotations to either fields constructor parameters on java.
*/
public enum MappingType {
EMBEDDED, EMBEDDED_GROUP, MAP, COLLECTION, DEFAULT, ENTITY;
EMBEDDED, EMBEDDED_GROUP, MAP, COLLECTION, DEFAULT, ENTITY, ARRAY;


/**
Expand Down Expand Up @@ -53,7 +53,9 @@ public static MappingType of(Class<?> type) {
var value = type.getAnnotation(Embeddable.class).value();
return value == Embeddable.EmbeddableType.FLAT ? MappingType.EMBEDDED : MappingType.EMBEDDED_GROUP;
}

if(type.isArray()) {
return MappingType.ARRAY;
}
return MappingType.DEFAULT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class Person {
@Column
private List<String> phones;

@Column
private String[] mobile;

private String ignore;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class Worker {
@Column
private Job job;

@Column
private Job[] freeLancer;

@Column("money")
@Convert(MoneyConverter.class)
private Money salary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ void shouldReturnDefault() throws NoSuchFieldException {
assertEquals(MappingType.DEFAULT, MappingType.of(field.getType()));
}

@Test
void shouldReturnArray() throws NoSuchFieldException {
Field field = Person.class.getDeclaredField("mobile");
assertEquals(MappingType.ARRAY, MappingType.of(field.getType()));
}

@Test
void shouldReturnArrayEntity() throws NoSuchFieldException {
Field field = Worker.class.getDeclaredField("freeLancer");
assertEquals(MappingType.ARRAY, MappingType.of(field.getType()));
}

@Test
void shouldReturnEmbedded() throws NoSuchFieldException {
Expand Down Expand Up @@ -129,6 +140,13 @@ void shouldReturnParameterEmbeddedGroup() {
assertEquals(MappingType.EMBEDDED_GROUP, MappingType.of(map.getType()));
}

@SuppressWarnings("unchecked")
@Test
void shouldReturnParameterEmbeddedArray() {
Constructor<Contacts> constructor = (Constructor<Contacts>) Contacts.class.getDeclaredConstructors()[0];
Parameter map = constructor.getParameters()[1];
assertEquals(MappingType.ARRAY, MappingType.of(map.getType()));
}

public static class ForClass {

Expand Down Expand Up @@ -163,4 +181,16 @@ public static class Bar2Class {
@Column("integerAnnotation")
private Integer integer;
}

public static class Contacts {
@Column
private String name;
@Column
private String[] mobile;

public Contacts(@Column String name, @Column String[] mobile) {
this.name = name;
this.mobile = mobile;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.reflection;

import jakarta.nosql.AttributeConverter;
import jakarta.nosql.Embeddable;
import jakarta.nosql.Entity;
import org.eclipse.jnosql.communication.TypeReference;
import org.eclipse.jnosql.communication.Value;
import org.eclipse.jnosql.mapping.metadata.ArrayFieldMetadata;
import org.eclipse.jnosql.mapping.metadata.MappingType;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

final class DefaultArrayFieldMetadata extends AbstractFieldMetadata implements ArrayFieldMetadata {

public static final TypeReference<List<Object>> TYPE_SUPPLIER = new TypeReference<>() {};
private final Class<?> elementType;

DefaultArrayFieldMetadata(MappingType type, Field field, String name, Class<?> elementType,
Class<? extends AttributeConverter<?, ?>> converter,
FieldReader reader, FieldWriter writer, String udt) {
super(type, field, name, converter, reader, writer, udt);
this.elementType = elementType;
}

@Override
public Object value(Value value) {
if(value.get() instanceof Iterable) {
return value.get(TYPE_SUPPLIER).toArray();
} else {
return Value.of(Collections.singletonList(value.get())).get(TYPE_SUPPLIER);
}
}

@Override
public boolean isId() {
return false;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultArrayFieldMetadata that = (DefaultArrayFieldMetadata) o;
return mappingType == that.mappingType &&
Objects.equals(field, that.field) &&
Objects.equals(elementType, that.elementType) &&
Objects.equals(name, that.name);
}



@Override
public int hashCode() {
return Objects.hash(mappingType, field, name, elementType);
}

@Override
public boolean isEmbeddable() {
return isEmbeddableField() || isEntityField();
}

private boolean isEntityField() {
return hasFieldAnnotation(Entity.class);
}

private boolean isEmbeddableField() {
return hasFieldAnnotation(Embeddable.class);
}

private boolean hasFieldAnnotation(Class<? extends Annotation> annotation) {
return elementType.getAnnotation(annotation) != null;
}

@Override
public Class<?> elementType() {
return elementType;
}

@Override
public Object arrayInstance(Collection<?> collection) {
var array = Array.newInstance(elementType, collection.size());
int index = 0;
for (Object item : collection) {
Array.set(array, index++, item);
}
return array;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.reflection;

import jakarta.nosql.AttributeConverter;
import org.eclipse.jnosql.mapping.metadata.ArrayParameterMetaData;
import org.eclipse.jnosql.mapping.metadata.MappingType;

import java.lang.reflect.Array;
import java.util.Collection;

class DefaultArrayParameterMetaData extends DefaultParameterMetaData implements ArrayParameterMetaData {


private final Class<?> elementType;

DefaultArrayParameterMetaData(String name, Class<?> type, boolean id,
Class<? extends AttributeConverter<?, ?>> converter,
MappingType mappingType, Class<?> elementType) {
super(name, type, id, converter, mappingType);
this.elementType = elementType;
}

@Override
public Class<?> elementType() {
return elementType;
}

@Override
public Object arrayInstance(Collection<?> collection) {
var array = Array.newInstance(elementType, collection.size());
int index = 0;
for (Object item : collection) {
Array.set(array, index++, item);
}
return array;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public Collection<?> collectionInstance() {

@Override
public String toString() {
return "GenericFieldMapping{" + "typeSupplier=" + typeSupplier +
return "DefaultCollectionFieldMetadata{" + "typeSupplier=" + typeSupplier +
", type=" + mappingType +
", field=" + field +
", name='" + name + '\'' +
Expand Down
Loading

0 comments on commit f8db987

Please sign in to comment.