Replace eclipselink converter with standard javax.persistence.Convert(er) (#2035)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-15 16:05:15 +02:00
committed by GitHub
parent 7fe8ad4f30
commit 4a46344ebe
2 changed files with 119 additions and 31 deletions

View File

@@ -9,15 +9,22 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.io.Serial;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.ConstraintMode;
import jakarta.persistence.Convert;
import jakarta.persistence.Converter;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
@@ -45,28 +52,30 @@ import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.persistence.annotations.ConversionValue;
import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.ObjectTypeConverter;
/**
* JPA implementation of {@link Action}.
*/
@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"),
@Index(name = "sp_idx_action_02", columnList = "tenant,target,active"),
@Index(name = "sp_idx_action_prim", columnList = "tenant,id") })
@Table(
name = "sp_action",
indexes = {
@Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"),
@Index(name = "sp_idx_action_02", columnList = "tenant,target,active"),
@Index(name = "sp_idx_action_prim", columnList = "tenant,id")
})
@NamedEntityGraphs({
@NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }),
@NamedEntityGraph(name = "Action.all", attributeNodes = {
@NamedAttributeNode("distributionSet"),
@NamedAttributeNode(value = "target", subgraph = "target.ds") },
subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) })
subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet")))
})
@Entity
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities
@SuppressWarnings("squid:S2160")
public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity {
@Serial
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@@ -86,13 +95,20 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Column(name = "active")
private boolean active;
@Converter
public static class ActionTypeConverter extends MapTypeConverter<ActionType, Integer> {
public ActionTypeConverter() {
super(Map.of(
ActionType.FORCED, 0,
ActionType.SOFT, 1,
ActionType.TIMEFORCED, 2,
ActionType.DOWNLOAD_ONLY, 3
));
}
}
@Column(name = "action_type", nullable = false)
@ObjectTypeConverter(name = "actionType", objectType = Action.ActionType.class, dataType = Integer.class, conversionValues = {
@ConversionValue(objectValue = "FORCED", dataValue = "0"),
@ConversionValue(objectValue = "SOFT", dataValue = "1"),
@ConversionValue(objectValue = "TIMEFORCED", dataValue = "2"),
@ConversionValue(objectValue = "DOWNLOAD_ONLY", dataValue = "3") })
@Convert("actionType")
@Convert(converter = ActionTypeConverter.class)
@NotNull
private ActionType actionType;
@@ -104,21 +120,28 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Max(Action.WEIGHT_MAX)
private Integer weight;
@Converter
public static class StatusConverter extends MapTypeConverter<Status, Integer> {
public StatusConverter() {
super(new HashMap<>() {{
put(Status.FINISHED, 0);
put(Status.ERROR, 1);
put(Status.WARNING, 2);
put(Status.RUNNING, 3);
put(Status.CANCELED, 4);
put(Status.CANCELING, 5);
put(Status.RETRIEVED, 6);
put(Status.DOWNLOAD, 7);
put(Status.SCHEDULED, 8);
put(Status.CANCEL_REJECTED, 9);
put(Status.DOWNLOADED, 10);
put(Status.WAIT_FOR_CONFIRMATION, 11);
}});
}
}
@Column(name = "status", nullable = false)
@ObjectTypeConverter(name = "status", objectType = Action.Status.class, dataType = Integer.class, conversionValues = {
@ConversionValue(objectValue = "FINISHED", dataValue = "0"),
@ConversionValue(objectValue = "ERROR", dataValue = "1"),
@ConversionValue(objectValue = "WARNING", dataValue = "2"),
@ConversionValue(objectValue = "RUNNING", dataValue = "3"),
@ConversionValue(objectValue = "CANCELED", dataValue = "4"),
@ConversionValue(objectValue = "CANCELING", dataValue = "5"),
@ConversionValue(objectValue = "RETRIEVED", dataValue = "6"),
@ConversionValue(objectValue = "DOWNLOAD", dataValue = "7"),
@ConversionValue(objectValue = "SCHEDULED", dataValue = "8"),
@ConversionValue(objectValue = "CANCEL_REJECTED", dataValue = "9"),
@ConversionValue(objectValue = "DOWNLOADED", dataValue = "10"),
@ConversionValue(objectValue = "WAIT_FOR_CONFIRMATION", dataValue = "11") })
@Convert("status")
@Convert(converter = StatusConverter.class)
@NotNull
private Status status;
@@ -401,4 +424,28 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
return getMaintenanceWindowStartTime()
.map(start -> start.plus(MaintenanceScheduleHelper.convertToISODuration(maintenanceWindowDuration)));
}
}
private static class MapTypeConverter<JAVA_TYPE extends Enum, DB_TYPE> implements AttributeConverter<JAVA_TYPE, DB_TYPE> {
private final Map<JAVA_TYPE, DB_TYPE> javaToDbMap;
private final Map<DB_TYPE, JAVA_TYPE> dbToJavaMap;
protected MapTypeConverter(final Map<JAVA_TYPE, DB_TYPE> javaToDbMap) {
this.javaToDbMap = javaToDbMap;
this.dbToJavaMap = javaToDbMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
if (javaToDbMap.size() != dbToJavaMap.size()) {
throw new IllegalArgumentException("Duplicate values in javaToDbMap");
}
}
@Override
public DB_TYPE convertToDatabaseColumn(final JAVA_TYPE attribute) {
return javaToDbMap.get(attribute);
}
@Override
public JAVA_TYPE convertToEntityAttribute(final DB_TYPE dbData) {
return dbToJavaMap.get(dbData);
}
}
}

View File

@@ -17,13 +17,16 @@ import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.junit.jupiter.api.Test;
@Feature("Unit Tests - Repository")
@Story("Deployment Management")
public class ActionTest {
public class ActionTest extends AbstractJpaIntegrationTest {
@Test
@Description("Ensures that timeforced moded switch from soft to forces after defined timeframe.")
@@ -41,4 +44,42 @@ public class ActionTest {
Awaitility.await().atMost(Duration.ofSeconds(2)).pollInterval(Duration.ofMillis(100))
.until(timeforcedAction::isForcedOrTimeForced);
}
@Test
public void testActionTypeConvert() {
final long id = createAction().getId();
for (final ActionType actionType : ActionType.values()) {
final JpaAction action = actionRepository
.findById(id).orElseThrow(() -> new IllegalStateException("Action not found"));
action.setActionType(actionType);
actionRepository.save(action);
assertThat(actionRepository.findById(id).orElseThrow(() -> new IllegalStateException("Action not found"))
.getActionType()).isEqualTo(actionType);
}
}
@Test
public void testStatusConvert() {
final long id = createAction().getId();
for (final Status status : Status.values()) {
final JpaAction action = actionRepository
.findById(id).orElseThrow(() -> new IllegalStateException("Action not found"));
action.setStatus(status);
actionRepository.save(action);
assertThat(actionRepository.findById(id).orElseThrow(() -> new IllegalStateException("Action not found"))
.getStatus()).isEqualTo(status);
}
}
private Action createAction() {
final ActionType[] actionTypes = ActionType.values();
final JpaAction action = new JpaAction();
action.setTarget(testdataFactory.createTarget("testActionTypeMappingTarget"));
action.setDistributionSet(testdataFactory.createDistributionSet("testActionTypeMappingDS"));
action.setActionType(actionTypes[0]);
action.setStatus(Status.SCHEDULED);
action.setWeight(100);
action.setInitiatedBy("none");
return actionRepository.save(action);
}
}