Feature/fix sonar warnings (#1226)

* Fixed sonar warnings

- "Cognitive Complexity"
- "Do not use replaceAll when not using a regex"
- java:S5869 - Character classes in regular expressions should not contain the same character twice
- Improved bad name
- Typos
- reduced code duplications
- Replaced hand-made wait-utility with Awaitility
- Log messages
- Duplicate code
- Typos
- Removed Thread.sleep, instead relaxed check condition
- Removed use of deprecated API
- Removed use of deprecated API
- Added supress-warnings as I do not see a better way to write the tests
- Removed Thread.sleep / redundant functionality to Awaitility
- Fixed other warnings (use isZero, isEmpty, hasToString)
- Removed/Reduced duplicate code
- Added generics
- Fixed asserts
- removed: field.setAccessible(true) actually should not be needed for public static fields!
- Too long constructor passes arguments in wrong order - how surprisingly...
- Clean-up use of varargs arguments
- Fixed regex
- Fixed typos and other minor stuff
- Making public constructors protected in abstract classes
- Swapped expected and asserted argument
- volatile not enough for syncing threads
- volatile not enough for syncing threads
- out-commented code
- Made regex not-greedy, added tests for verification
- Avoid exposure of thread-local member var

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Fixed Sonar warnings

* License header fix

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* License header fix #2

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Fixing review findings

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>

* Fixing tests

- Fixed '&' usage in javadoc and typos
- Fixing some warnings

Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>
This commit is contained in:
Peter Vigier
2022-01-31 21:59:46 +01:00
committed by GitHub
parent 5443b5df9c
commit 44a85f20eb
98 changed files with 2583 additions and 2702 deletions

View File

@@ -14,6 +14,7 @@ import javax.persistence.PersistenceException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
import org.springframework.lang.NonNull;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
@@ -53,13 +54,12 @@ public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
private static final SQLStateSQLExceptionTranslator SQLSTATE_EXCEPTION_TRANSLATOR = new SQLStateSQLExceptionTranslator();
@Override
public DataAccessException translateExceptionIfPossible(final RuntimeException ex) {
public DataAccessException translateExceptionIfPossible(@NonNull final RuntimeException ex) {
final DataAccessException dataAccessException = super.translateExceptionIfPossible(ex);
if (dataAccessException == null) {
return searchAndTranslateSqlException(ex);
}
return translateJpaSystemExceptionIfPossible(dataAccessException);
}
@@ -69,22 +69,19 @@ public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
return accessException;
}
final DataAccessException sql = searchAndTranslateSqlException(accessException);
if (sql == null) {
final DataAccessException sqlException = searchAndTranslateSqlException(accessException);
if (sqlException == null) {
return accessException;
}
return sql;
return sqlException;
}
private static DataAccessException searchAndTranslateSqlException(final RuntimeException ex) {
final SQLException sqlException = findSqlException(ex);
if (sqlException == null) {
return null;
}
return SQLSTATE_EXCEPTION_TRANSLATOR.translate(null, null, sqlException);
return SQLSTATE_EXCEPTION_TRANSLATOR.translate("", null, sqlException);
}
private static SQLException findSqlException(final RuntimeException jpaSystemException) {

View File

@@ -767,7 +767,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
final JpaAction action = actionRepository.findById(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
if (!action.isForce()) {
if (!action.isForcedOrTimeForced()) {
action.setActionType(ActionType.FORCED);
return actionRepository.save(action);
}

View File

@@ -9,7 +9,6 @@
package org.eclipse.hawkbit.repository.jpa;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -25,7 +24,6 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
@@ -202,11 +200,11 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
// Create if it does not exist
if (result == null) {
try {
currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant);
currentTenantCacheKeyGenerator.setTenantInCreation(tenant);
return createInitialTenantMetaData(tenant);
} finally {
currentTenantCacheKeyGenerator.getCreateInitialTenant().remove();
currentTenantCacheKeyGenerator.removeTenantInCreation();
}
}
return result;
@@ -276,20 +274,17 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
if (tenantAware.getCurrentTenant() == null) {
throw new IllegalStateException("Tenant not set");
}
return getTenantMetadata(tenantAware.getCurrentTenant());
}
@Override
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
public String currentTenant() {
final String initialTenantCreation = currentTenantCacheKeyGenerator.getCreateInitialTenant().get();
if (initialTenantCreation == null) {
return currentTenantCacheKeyGenerator.getTenantInCreation().orElseGet(() -> {
final TenantMetaData findByTenant = tenantMetaDataRepository
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
return findByTenant != null ? findByTenant.getTenant() : null;
}
return initialTenantCreation;
});
}
@Override
@@ -312,7 +307,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
Integer.MAX_VALUE));
final SoftwareModuleType os = softwareModuleTypeRepository.save(new JpaSoftwareModuleType(
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_KEY,
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_NAME, "Core firmware or operationg system", 1));
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_NAME, "Core firmware or operation system", 1));
// make sure the module types get their IDs
entityManager.flush();

View File

@@ -9,6 +9,10 @@
package org.eclipse.hawkbit.repository.jpa;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Optional;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,7 +22,6 @@ import org.springframework.context.annotation.Bean;
/**
* Implementation of {@link CurrentTenantCacheKeyGenerator}.
*
*/
public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator {
@@ -28,25 +31,17 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
/**
* A implementation of the {@link KeyGenerator} to generate a key based on
* An implementation of the {@link KeyGenerator} to generate a key based on
* either the {@code createInitialTenant} thread local and the
* {@link TenantAware}, but in case we are in a tenant creation with its
* default types we need to use the tenant the current tenant which is
* currently created and not the one currently in the {@link TenantAware}.
*
* {@link TenantAware}, but in case we are in a tenant creation with its default
* types we need to use as the tenant the current tenant which is currently
* created and not the one currently in the {@link TenantAware}.
*/
public class CurrentTenantKeyGenerator implements KeyGenerator {
@Override
// Exception squid:S923 - override
@SuppressWarnings({ "squid:S923" })
public Object generate(final Object target, final Method method, final Object... params) {
final String initialTenantCreation = createInitialTenant.get();
if (initialTenantCreation == null) {
return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(),
tenantAware.getCurrentTenant().toUpperCase());
}
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
initialTenantCreation.toUpperCase());
String tenant = getTenantInCreation().orElseGet(() -> tenantAware.getCurrentTenant()).toUpperCase();
return SimpleKeyGenerator.generateKey(tenant, tenant);
}
}
@@ -56,8 +51,33 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
return new CurrentTenantKeyGenerator();
}
ThreadLocal<String> getCreateInitialTenant() {
return createInitialTenant;
/**
* Get the tenant which overwrites the actual tenant used by the
* {@linkplain #currentTenantKeyGenerator()}.
*
* @return A present optional in case that there is a tenant in the progress of
* creation.
*/
public Optional<String> getTenantInCreation() {
return Optional.ofNullable(createInitialTenant.get());
}
/**
* Overwrite the tenant used by the key generator in case that the tenant is in
* the process of creation.
*
* @param tenant
* the tenant which should be used instead of the actual one.
*/
public void setTenantInCreation(@NotNull String tenant) {
createInitialTenant.set(Objects.requireNonNull(tenant));
}
/**
* Removes the tenant overwriting the standard one used by the
* {@linkplain #currentTenantKeyGenerator()}.
*/
public void removeTenantInCreation() {
createInitialTenant.remove();
}
}

View File

@@ -8,7 +8,10 @@
*/
package org.eclipse.hawkbit.repository.jpa.configuration;
import java.util.Objects;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.transaction.Transaction;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -37,8 +40,10 @@ public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
final String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant != null) {
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
.getResource(getEntityManagerFactory());
final EntityManagerFactory emFactory = Objects.requireNonNull(getEntityManagerFactory());
final EntityManagerHolder emHolder = Objects.requireNonNull(
(EntityManagerHolder) TransactionSynchronizationManager.getResource(emFactory),
"No EntityManagerHolder provided by TransactionSynchronizationManager");
final EntityManager em = emHolder.getEntityManager();
em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, currentTenant.toUpperCase());
}

View File

@@ -55,34 +55,34 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
/**
* Default constructor needed for JPA entities.
*/
public AbstractJpaBaseEntity() {
protected AbstractJpaBaseEntity() {
// Default constructor needed for JPA entities.
}
@Override
@Access(AccessType.PROPERTY)
@Column(name = "created_at", insertable = true, updatable = false, nullable = false)
@Column(name = "created_at", updatable = false, nullable = false)
public long getCreatedAt() {
return createdAt;
}
@Override
@Access(AccessType.PROPERTY)
@Column(name = "created_by", insertable = true, updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
@Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
public String getCreatedBy() {
return createdBy;
}
@Override
@Access(AccessType.PROPERTY)
@Column(name = "last_modified_at", insertable = true, updatable = true, nullable = false)
@Column(name = "last_modified_at", nullable = false)
public long getLastModifiedAt() {
return lastModifiedAt;
}
@Override
@Access(AccessType.PROPERTY)
@Column(name = "last_modified_by", insertable = true, updatable = true, nullable = false, length = USERNAME_FIELD_LENGTH)
@Column(name = "last_modified_by", nullable = false, length = USERNAME_FIELD_LENGTH)
public String getLastModifiedBy() {
return lastModifiedBy;
}

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Objects;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Id;
@@ -36,12 +38,12 @@ public abstract class AbstractJpaMetaData implements MetaData {
@Basic
private String value;
public AbstractJpaMetaData(final String key, final String value) {
protected AbstractJpaMetaData(final String key, final String value) {
this.key = key;
this.value = value;
}
public AbstractJpaMetaData() {
protected AbstractJpaMetaData() {
// Default constructor needed for JPA entities
}
@@ -64,41 +66,17 @@ public abstract class AbstractJpaMetaData implements MetaData {
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final AbstractJpaMetaData that = (AbstractJpaMetaData) o;
return Objects.equals(key, that.key) && Objects.equals(value, that.value);
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(this.getClass().isInstance(obj))) {
return false;
}
final AbstractJpaMetaData other = (AbstractJpaMetaData) obj;
if (key == null) {
if (other.key != null) {
return false;
}
} else if (!key.equals(other.key)) {
return false;
}
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
public int hashCode() {
return Objects.hash(key, value);
}
}

View File

@@ -32,14 +32,14 @@ public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseE
@NotNull
private String name;
@Column(name = "description", nullable = true, length = NamedEntity.DESCRIPTION_MAX_SIZE)
@Column(name = "description", length = NamedEntity.DESCRIPTION_MAX_SIZE)
@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE)
private String description;
/**
* Default constructor.
*/
public AbstractJpaNamedEntity() {
protected AbstractJpaNamedEntity() {
// Default constructor needed for JPA entities
}

View File

@@ -40,7 +40,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
/**
* Default constructor needed for JPA entities.
*/
public AbstractJpaTenantAwareBaseEntity() {
protected AbstractJpaTenantAwareBaseEntity() {
// Default constructor needed for JPA entities.
}

View File

@@ -299,22 +299,10 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
}
}
public boolean removeModule(final SoftwareModule softwareModule) {
if (modules == null) {
return false;
}
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findAny();
if (found.isPresent()) {
modules.remove(found.get());
public void removeModule(final SoftwareModule softwareModule) {
if (modules != null && modules.removeIf(m -> m.getId().equals(softwareModule.getId()))) {
complete = type.checkComplete(this);
return true;
}
return false;
}
@Override
@@ -371,11 +359,11 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
private static boolean isSoftDeleted(final DescriptorEvent event) {
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
.collect(Collectors.toList());
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
}
}

View File

@@ -278,11 +278,11 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
private static boolean isSoftDeleted(final DescriptorEvent event) {
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
.collect(Collectors.toList());
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
}
@Override

View File

@@ -258,11 +258,11 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
private static boolean isSoftDeleted(final DescriptorEvent event) {
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
.collect(Collectors.toList());
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
}
@Override

View File

@@ -96,7 +96,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
@Column(name = "controller_id", length = Target.CONTROLLER_ID_MAX_SIZE, updatable = false, nullable = false)
@Size(min = 1, max = Target.CONTROLLER_ID_MAX_SIZE)
@NotNull
@Pattern(regexp = "[.\\S]*", message = "has whitespaces which are not allowed")
@Pattern(regexp = "[\\S]*", message = "has whitespaces which are not allowed")
private String controllerId;
@CascadeOnDelete
@@ -243,34 +243,28 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
if (rolloutTargetGroup == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(rolloutTargetGroup);
}
/**
* @param tag
* tag
* @return boolean true or false
* to be added
*/
public boolean addTag(final TargetTag tag) {
public void addTag(final TargetTag tag) {
if (tags == null) {
tags = new HashSet<>();
}
return tags.add(tag);
tags.add(tag);
}
/**
* @param tag
* tag
* @return boolean true or false
* the tag to be removed from the target
*/
public boolean removeTag(final TargetTag tag) {
if (tags == null) {
return false;
public void removeTag(final TargetTag tag) {
if (tags != null) {
tags.remove(tag);
}
return tags.remove(tag);
}
/**
@@ -303,14 +297,12 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
/**
* @param action
* Action
* @return boolean true or false
*/
public boolean addAction(final Action action) {
public void addAction(final Action action) {
if (actions == null) {
actions = new ArrayList<>();
}
return actions.add((JpaAction) action);
actions.add((JpaAction) action);
}
/**

View File

@@ -12,6 +12,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.FieldNameProvider;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.slf4j.Logger;
@@ -25,7 +27,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
private final Class<A> fieldNameProvider;
public AbstractFieldNameRSQLVisitor(final Class<A> fieldNameProvider) {
protected AbstractFieldNameRSQLVisitor(final Class<A> fieldNameProvider) {
this.fieldNameProvider = fieldNameProvider;
}
@@ -51,7 +53,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
// sub entity need minimum 1 dot
if (!propertyEnum.getSubEntityAttributes().isEmpty() && graph.length < 2) {
throw createRSQLParameterUnsupportedException(node);
throw createRSQLParameterUnsupportedException(node, null);
}
final StringBuilder fieldNameBuilder = new StringBuilder(propertyEnum.getFieldName());
@@ -67,7 +69,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
}
if (!propertyEnum.containsSubEntityAttribute(propertyField)) {
throw createRSQLParameterUnsupportedException(node);
throw createRSQLParameterUnsupportedException(node, null);
}
}
@@ -93,30 +95,21 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
}
}
/**
* @param node
* current processing node
* @param rootException
* in case there is a cause otherwise {@code null}
* @return Exception with prepared message extracted from the comparison node.
*/
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(
final ComparisonNode node) {
return createRSQLParameterUnsupportedException(node, new Exception());
}
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final ComparisonNode node,
@NotNull final ComparisonNode node,
final Exception rootException) {
return createRSQLParameterUnsupportedException(String.format(
return new RSQLParameterUnsupportedFieldException(String.format(
"The given search parameter field {%s} does not exist, must be one of the following fields %s",
node.getSelector(), getExpectedFieldList()), rootException);
}
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final String message) {
return createRSQLParameterUnsupportedException(message, null);
}
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final String message,
final Exception rootException) {
return new RSQLParameterUnsupportedFieldException(message, rootException);
}
// Exception squid:S2095 - see
// https://jira.sonarsource.com/browse/SONARJAVA-1478
@SuppressWarnings({ "squid:S2095" })
private List<String> getExpectedFieldList() {
final List<String> expectedFieldList = Arrays.stream(fieldNameProvider.getEnumConstants())
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {

View File

@@ -181,7 +181,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
return (Path<Object>) getFieldPath(root, enumField.getSubAttributes(finalProperty), enumField.isMap(),
this::getJoinFieldPath).orElseThrow(
() -> createRSQLParameterUnsupportedException("RSQL field path cannot be empty", null));
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
}
@SuppressWarnings("unchecked")
@@ -279,7 +279,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
private Object convertFieldConverterValue(final ComparisonNode node, final A fieldName, final String value) {
final Object convertedValue = ((FieldValueConverter) fieldName).convertValue(fieldName, value);
if (convertedValue == null) {
throw createRSQLParameterUnsupportedException(
throw new RSQLParameterUnsupportedFieldException(
"field {" + node.getSelector() + "} must be one of the following values {"
+ Arrays.toString(((FieldValueConverter) fieldName).possibleValues(fieldName)) + "}",
null);

View File

@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import java.lang.reflect.Field;
import java.util.Arrays;
import com.google.common.base.Throwables;
import org.springframework.util.ReflectionUtils;
import cz.jirutka.rsql.parser.ParseException;
@@ -24,13 +24,7 @@ import cz.jirutka.rsql.parser.ParseException;
*/
public class ParseExceptionWrapper {
private static final String FIELD_EXPECTED_TOKEN_SEQ = "expectedTokenSequences";
private static final String FIELD_CURRENT_TOKEN = "currentToken";
private final ParseException parseException;
private final Class<? extends ParseException> parseExceptionClass;
private Field expectedTokenSequenceField;
private Field currentTokenField;
/**
* Constructor.
@@ -41,33 +35,24 @@ public class ParseExceptionWrapper {
*/
public ParseExceptionWrapper(final ParseException parseException) {
this.parseException = parseException;
parseExceptionClass = parseException.getClass();
try {
expectedTokenSequenceField = getAccessibleField(parseExceptionClass, FIELD_EXPECTED_TOKEN_SEQ);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
expectedTokenSequenceField = null;
}
try {
currentTokenField = getAccessibleField(parseExceptionClass, FIELD_CURRENT_TOKEN);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
currentTokenField = null;
}
}
public int[][] getExpectedTokenSequence() {
if (expectedTokenSequenceField == null) {
return new int[0][0];
}
return (int[][]) getValue(expectedTokenSequenceField, parseException);
return (parseException.expectedTokenSequences != null) // unclear if this can happen
? parseException.expectedTokenSequences
: new int[0][0];
}
/**
* Get the current token
*
* @return the current token or {@code null} if there is non.
*/
public TokenWrapper getCurrentToken() {
if (currentTokenField == null) {
return null;
}
return new TokenWrapper(getValue(currentTokenField, parseException));
return (parseException.currentToken != null) // unclear if this can happen
? new TokenWrapper(parseException.currentToken)
: null;
}
@Override
@@ -76,19 +61,6 @@ public class ParseExceptionWrapper {
+ ", getCurrentToken()=" + getCurrentToken() + "]";
}
private static Field getAccessibleField(final Class<?> clazz, final String field) throws NoSuchFieldException {
final Field declaredField = clazz.getDeclaredField(field);
declaredField.setAccessible(true);
return declaredField;
}
private static Object getValue(final Field field, final Object instance) {
try {
return field.get(instance);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw Throwables.propagate(e);
}
}
/**
* A {@link TokenWrapper} which wraps the
@@ -115,37 +87,37 @@ public class ParseExceptionWrapper {
this.tokenInstance = tokenField;
try {
nextTokenField = getAccessibleField(tokenField.getClass(), FIELD_NEXT);
nextTokenField = getAccessibleField(FIELD_NEXT);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
nextTokenField = null;
}
try {
kindTokenField = getAccessibleField(tokenField.getClass(), FIELD_KIND);
kindTokenField = getAccessibleField(FIELD_KIND);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
kindTokenField = null;
}
try {
imageTokenField = getAccessibleField(tokenField.getClass(), FIELD_IMAGE);
imageTokenField = getAccessibleField(FIELD_IMAGE);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
imageTokenField = null;
}
try {
beginColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_BEGIN_COL);
beginColumnTokenField = getAccessibleField(FIELD_BEGIN_COL);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
beginColumnTokenField = null;
}
try {
endColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_END_COL);
endColumnTokenField = getAccessibleField(FIELD_END_COL);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
endColumnTokenField = null;
}
}
public TokenWrapper getNext() {
final Object nextToken = getValue(nextTokenField, tokenInstance);
final Object nextToken = getValue(nextTokenField);
return nextToken != null ? new TokenWrapper(nextToken) : null;
}
@@ -154,28 +126,42 @@ public class ParseExceptionWrapper {
if (kindTokenField == null) {
return 0;
}
return (int) getValue(kindTokenField, tokenInstance);
return (int) getValue(kindTokenField);
}
public String getImage() {
if (imageTokenField == null) {
return null;
}
return (String) getValue(imageTokenField, tokenInstance);
return (String) getValue(imageTokenField);
}
public int getBeginColumn() {
if (beginColumnTokenField == null) {
return 0;
}
return (int) getValue(beginColumnTokenField, tokenInstance);
return (int) getValue(beginColumnTokenField);
}
public int getEndColumn() {
if (endColumnTokenField == null) {
return 0;
}
return (int) getValue(endColumnTokenField, tokenInstance);
return (int) getValue(endColumnTokenField);
}
private Field getAccessibleField(final String field) throws NoSuchFieldException {
final Field declaredField = tokenInstance.getClass().getDeclaredField(field);
ReflectionUtils.makeAccessible(declaredField);
return declaredField;
}
private Object getValue(final Field field) {
try {
return field.get(tokenInstance);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalFieldAccessExeption(e);
}
}
@Override
@@ -185,4 +171,11 @@ public class ParseExceptionWrapper {
+ ", getEndColumn()=" + getEndColumn() + "]";
}
}
static class IllegalFieldAccessExeption extends RuntimeException {
public IllegalFieldAccessExeption(Throwable e) {
super(e);
}
}
}

View File

@@ -116,7 +116,7 @@ public class RsqlParserValidationOracle implements RsqlValidationOracle {
private static List<SuggestToken> getNextTokens(final ParseException parseException) {
final List<SuggestToken> listTokens = new ArrayList<>();
final ParseExceptionWrapper parseExceptionWrapper = new ParseExceptionWrapper(parseException);
final int[][] expectedTokenSequence = parseExceptionWrapper.getExpectedTokenSequence();
final int[][] expectedTokenSequence = parseException.expectedTokenSequences;
final TokenWrapper currentToken = parseExceptionWrapper.getCurrentToken();
if (currentToken == null) {
return Collections.emptyList();
@@ -243,8 +243,8 @@ public class RsqlParserValidationOracle implements RsqlValidationOracle {
}
builder = builder.replace('\r', ' ');
builder = builder.replace('\n', ' ');
builder = builder.replaceAll(">", " ");
builder = builder.replaceAll("<", " ");
builder = builder.replace(">", " ");
builder = builder.replace("<", " ");
return builder;
}