Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
rajkp10 committed Apr 1, 2024
1 parent b026790 commit 9da1616
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -706,17 +706,21 @@ private Optional<String> getDocumentScoreField(List<java.lang.reflect.Field> all
.map(field -> (isDocument ? "$." : "") + field.getName());
}

private boolean isAnnotationPreset(java.lang.reflect.Field idField, List<SchemaField> fields){
return (!idField.isAnnotationPresent(Indexed.class)
&& !idField.isAnnotationPresent(Searchable.class)
&& !idField.isAnnotationPresent(TagIndexed.class)
&& !idField.isAnnotationPresent(TextIndexed.class)
&& (fields.stream().noneMatch(f -> f.getName().equals(idField.getName()))));
}

private Optional<SchemaField> createIndexedFieldForIdField(Class<?> cl, List<SchemaField> fields, boolean isDocument) {
Optional<SchemaField> result = Optional.empty();
Optional<java.lang.reflect.Field> maybeIdField = getIdFieldForEntityClass(cl);
if (maybeIdField.isPresent()) {
java.lang.reflect.Field idField = maybeIdField.get();
// Only auto-index the @Id if not already indexed by the user (gh-135)
if (!idField.isAnnotationPresent(Indexed.class)
&& !idField.isAnnotationPresent(Searchable.class)
&& !idField.isAnnotationPresent(TagIndexed.class)
&& !idField.isAnnotationPresent(TextIndexed.class)
&& (fields.stream().noneMatch(f -> f.getName().equals(idField.getName())))) {
if (isAnnotationPreset(idField, fields)) {
Class<?> idClass = idField.getType();
if (idField.getType().isPrimitive()) {
String cls = com.redis.om.spring.util.ObjectUtils.getTargetClassName(idClass.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ public void write(Object source, RedisData sink) {
typeMapper.writeType(ClassUtils.getUserClass(source), sink.getBucket().getPath());
}

writeEntity(entity, source, sink);
}

private void writeEntity(RedisPersistentEntity<?> entity, Object source, RedisData sink) {
if (entity == null) {
typeMapper.writeType(ClassUtils.getUserClass(source), sink.getBucket().getPath());
sink.getBucket().put("_raw", conversionService.convert(source, byte[].class));
Expand All @@ -345,7 +349,7 @@ public void write(Object source, RedisData sink) {

if (entity.getTypeInformation().isCollectionLike()) {
writeCollection(entity.getType(), entity.getKeySpace(), "", (List) source,
entity.getTypeInformation().getRequiredComponentType(), sink);
entity.getTypeInformation().getRequiredComponentType(), sink);
} else {
writeInternal(entity.getKeySpace(), "", source, entity.getTypeInformation(), sink);
}
Expand Down
17 changes: 17 additions & 0 deletions redis-om-spring/src/main/java/com/redis/om/spring/id/OsTools.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.redis.om.spring.id;

import java.util.Arrays;
import java.util.List;

public class OsTools {
private static final String OPERATING_SYSTEM_NAME = System.getProperty("os.name").toLowerCase();

private static final List<String> SECURE_RANDOM_ALGORITHMS_LINUX_OSX_SOLARIS = Arrays.asList("NativePRNGBlocking",
"NativePRNGNonBlocking", "NativePRNG", "SHA1PRNG");
private static final List<String> SECURE_RANDOM_ALGORITHMS_WINDOWS = Arrays.asList("SHA1PRNG", "Windows-PRNG");

static List<String> secureRandomAlgorithmNames() {
return OPERATING_SYSTEM_NAME.contains("win") ? SECURE_RANDOM_ALGORITHMS_WINDOWS
: SECURE_RANDOM_ALGORITHMS_LINUX_OSX_SOLARIS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.redis.om.spring.id;

import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.StringUtils;

import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicReference;

public class SecureRandom {
private static final AtomicReference<java.security.SecureRandom> secureRandom = new AtomicReference<>(null);

public static java.security.SecureRandom getSecureRandom() {
return secureRandom.updateAndGet(sr -> sr != null ? sr : createSecureRandom());
}

private static java.security.SecureRandom createSecureRandom() {
for (String algorithm : OsTools.secureRandomAlgorithmNames()) {
try {
return java.security.SecureRandom.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// ignore and try the next algorithm.
}
}

throw new InvalidDataAccessApiUsageException("Could not create SecureRandom instance for any of the specified algorithms: "
+ StringUtils.collectionToCommaDelimitedString(OsTools.secureRandomAlgorithmNames()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,11 @@
import org.springframework.data.keyvalue.core.IdentifierGenerator;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

public enum ULIDIdentifierGenerator implements IdentifierGenerator {

INSTANCE;

private final AtomicReference<SecureRandom> secureRandom = new AtomicReference<>(null);

@SuppressWarnings("unchecked")
@Override
public <T> T generateIdentifierOfType(TypeInformation<T> identifierType) {
Expand All @@ -30,53 +21,17 @@ public <T> T generateIdentifierOfType(TypeInformation<T> identifierType) {
} else if (ClassUtils.isAssignable(String.class, type)) {
return (T) UlidCreator.getMonotonicUlid().toString();
} else if (ClassUtils.isAssignable(Integer.class, type)) {
return (T) Integer.valueOf(getSecureRandom().nextInt());
return (T) Integer.valueOf(SecureRandom.getSecureRandom().nextInt());
} else if (ClassUtils.isAssignable(Long.class, type)) {
return (T) Long.valueOf(getSecureRandom().nextLong());
return (T) Long.valueOf(SecureRandom.getSecureRandom().nextLong());
}

throw new InvalidDataAccessApiUsageException(
String.format("Identifier cannot be generated for %s. Supported types are: ULID, String, Integer, and Long.",
identifierType.getType().getName()));
}

private SecureRandom getSecureRandom() {

SecureRandom sr = this.secureRandom.get();
if (sr != null) {
return sr;
}

for (String algorithm : OsTools.secureRandomAlgorithmNames()) {
try {
sr = SecureRandom.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// ignore and try next.
}
}

if (sr == null) {
throw new InvalidDataAccessApiUsageException(
String.format("Could not create SecureRandom instance for one of the algorithms '%s'.",
StringUtils.collectionToCommaDelimitedString(OsTools.secureRandomAlgorithmNames())));
}

this.secureRandom.compareAndSet(null, sr);

return sr;
String.format("Identifier cannot be generated for %s. Supported types are: ULID, String, Integer, and Long.",
identifierType.getType().getName()));
}
}

private static class OsTools {

private static final String OPERATING_SYSTEM_NAME = System.getProperty("os.name").toLowerCase();

private static final List<String> SECURE_RANDOM_ALGORITHMS_LINUX_OSX_SOLARIS = Arrays.asList("NativePRNGBlocking",
"NativePRNGNonBlocking", "NativePRNG", "SHA1PRNG");
private static final List<String> SECURE_RANDOM_ALGORITHMS_WINDOWS = Arrays.asList("SHA1PRNG", "Windows-PRNG");

static List<String> secureRandomAlgorithmNames() {
return OPERATING_SYSTEM_NAME.contains("win") ? SECURE_RANDOM_ALGORITHMS_WINDOWS
: SECURE_RANDOM_ALGORITHMS_LINUX_OSX_SOLARIS;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ private Map<? extends Element, String> getInstanceFields(Element element) {
// todo: Filter out methods only returning boolean or Boolean
.map(Element::getSimpleName).map(Object::toString).filter(n -> n.startsWith(IS_PREFIX))
.map(n -> n.substring(2))
.map(ObjectUtils::lcfirst).collect(Collectors.toSet());
.map(ObjectUtils::toLowercaseFirstCharacter).collect(Collectors.toSet());

// Retrieve all declared non-final instance fields of the annotated class
Map<Element, String> results = element.getEnclosedElements().stream()
Expand Down Expand Up @@ -685,7 +685,7 @@ private String findGetter(final Element field, final Map<String, Element> getter
return entityName + "::" + standardGetterName;
}

final String lambdaName = ObjectUtils.lcfirst(entityName);
final String lambdaName = ObjectUtils.toLowercaseFirstCharacter(entityName);

if (!field.getModifiers().contains(Modifier.PROTECTED) && !field.getModifiers().contains(Modifier.PRIVATE)) {
// We can use a lambda. Great escape hatch!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public RediSearchQuery(//
this.returnFields = new String[] {};
} else if (queryMethod.getName().startsWith("getAll")) {
this.type = RediSearchQueryType.TAGVALS;
this.value = ObjectUtils.lcfirst(queryMethod.getName().substring(6));
this.value = ObjectUtils.toLowercaseFirstCharacter(queryMethod.getName().substring(6));
} else if (queryMethod.getName().startsWith(AutoCompleteQueryExecutor.AUTOCOMPLETE_PREFIX)) {
this.type = RediSearchQueryType.AUTOCOMPLETE;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public RedisEnhancedQuery(
this.returnFields = new String[] {};
} else if (queryMethod.getName().startsWith("getAll")) {
this.type = RediSearchQueryType.TAGVALS;
this.value = ObjectUtils.lcfirst(queryMethod.getName().substring(6));
this.value = ObjectUtils.toLowercaseFirstCharacter(queryMethod.getName().substring(6));
} else if (queryMethod.getName().startsWith(AutoCompleteQueryExecutor.AUTOCOMPLETE_PREFIX)) {
this.type = RediSearchQueryType.AUTOCOMPLETE;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

Expand Down Expand Up @@ -55,7 +56,7 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon
reference = deserializeEntity(jsonObject, context);
} else if (json.isJsonArray()) {
JsonArray jsonArray = json.getAsJsonArray();
reference = ObjectUtils.instantiateCollection(typeOfT);
reference = instantiateCollection(typeOfT);

String[] keys = jsonArray.asList().stream().filter(JsonElement::isJsonPrimitive).map(jsonElement -> ObjectUtils.unQuote(jsonElement.toString())).toArray(String[]::new);
if (keys.length > 0) {
Expand All @@ -69,6 +70,27 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon
return reference;
}

public Collection<?> instantiateCollection(Type type) {
Class<?> rawType = (Class<?>) ((ParameterizedType) type).getRawType();
if (rawType.isInterface()) {
if (List.class.isAssignableFrom(rawType)) {
return new ArrayList<>();
} else if (Set.class.isAssignableFrom(rawType)) {
return new HashSet<>();
} else if (Queue.class.isAssignableFrom(rawType)) {
return new LinkedList<>();
} else {
throw new IllegalArgumentException("Unsupported interface: " + rawType);
}
} else {
try {
return (Collection<?>) rawType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Type not instantiatable: " + rawType);
}
}
}

private Object deserializeEntity(JsonObject jsonObject, JsonDeserializationContext context) {
Object reference = objectConstructor.construct();
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;

public abstract class AbstractTuple extends BasicAbstractTuple<AbstractTuple, Object> implements Tuple {

protected AbstractTuple(Class<? extends AbstractTuple> baseClass, String[] labels, Object... values) {
Expand All @@ -20,6 +22,14 @@ public Object get(int index) {
return values[assertIndexBounds(index)];
}

protected int assertIndexBounds(int index) {
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException(
"index " + index + " is illegal. The degree of this Tuple is " + size() + ".");
}
return index;
}

@Override
public Stream<Object> stream() {
return Stream.of(values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public abstract class BasicAbstractTuple<T extends GenericTuple<R>, R> implement
requireNonNull(values);
this.baseClass = requireNonNull(baseClass);
this.labels = labels;

if (!isNullable()) {
for (Object v : values) {
requireNonNull(v, () -> getClass().getName() + " cannot hold null values.");
Expand All @@ -36,14 +36,6 @@ public abstract class BasicAbstractTuple<T extends GenericTuple<R>, R> implement

protected abstract boolean isNullable();

protected int assertIndexBounds(int index) {
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException(
"index " + index + " is illegal. The degree of this Tuple is " + size() + ".");
}
return index;
}

@Override
public int hashCode() {
return Objects.hash(values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public static boolean isFirstLowerCase(String string) {
* @param input The text.
* @return The resulting text.
*/
public static String lcfirst(String input) {
public static String toLowercaseFirstCharacter(String input) {
return withFirst(input, first -> String.valueOf(Character.toLowerCase(first)));
}

Expand Down Expand Up @@ -429,26 +429,26 @@ public static float[] byteArrayToFloatArray(byte[] bytes) {
return floatArray;
}

public static Collection<?> instantiateCollection(Type type) {
Class<?> rawType = (Class<?>) ((ParameterizedType) type).getRawType();
if (rawType.isInterface()) {
if (List.class.isAssignableFrom(rawType)) {
return new ArrayList<>();
} else if (Set.class.isAssignableFrom(rawType)) {
return new HashSet<>();
} else if (Queue.class.isAssignableFrom(rawType)) {
return new LinkedList<>();
} else {
throw new IllegalArgumentException("Unsupported interface: " + rawType);
}
} else {
try {
return (Collection<?>) rawType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Type not instantiatable: " + rawType);
}
}
}
// public static Collection<?> instantiateCollection(Type type) {
// Class<?> rawType = (Class<?>) ((ParameterizedType) type).getRawType();
// if (rawType.isInterface()) {
// if (List.class.isAssignableFrom(rawType)) {
// return new ArrayList<>();
// } else if (Set.class.isAssignableFrom(rawType)) {
// return new HashSet<>();
// } else if (Queue.class.isAssignableFrom(rawType)) {
// return new LinkedList<>();
// } else {
// throw new IllegalArgumentException("Unsupported interface: " + rawType);
// }
// } else {
// try {
// return (Collection<?>) rawType.getDeclaredConstructor().newInstance();
// } catch (Exception e) {
// throw new IllegalArgumentException("Type not instantiatable: " + rawType);
// }
// }
// }

public static boolean isPrimitiveOfType(Class<?> clazz, Class<?> wrapper) {
return clazz.isPrimitive() && resolvePrimitiveIfNecessary(clazz) == wrapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,10 @@ void testIsFirstLowerCase() {

@Test
void testLcfirst() {
assertThat(ObjectUtils.lcfirst("Spam")).isEqualTo("spam");
assertThat(ObjectUtils.lcfirst("spam")).isEqualTo("spam");
assertThat(ObjectUtils.lcfirst("*light")).isEqualTo("*light");
assertThat(ObjectUtils.lcfirst("8675309")).isEqualTo("8675309");
assertThat(ObjectUtils.toLowercaseFirstCharacter("Spam")).isEqualTo("spam");
assertThat(ObjectUtils.toLowercaseFirstCharacter("spam")).isEqualTo("spam");
assertThat(ObjectUtils.toLowercaseFirstCharacter("*light")).isEqualTo("*light");
assertThat(ObjectUtils.toLowercaseFirstCharacter("8675309")).isEqualTo("8675309");
}

@Test
Expand Down

0 comments on commit 9da1616

Please sign in to comment.