GremlinUtils.java
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.spring.data.gremlin.common;
import com.azure.spring.data.gremlin.annotation.GeneratedValue;
import com.azure.spring.data.gremlin.conversion.source.GremlinSource;
import com.azure.spring.data.gremlin.exception.GremlinIllegalConfigurationException;
import com.azure.spring.data.gremlin.exception.GremlinInvalidEntityIdFieldException;
import com.azure.spring.data.gremlin.exception.GremlinUnexpectedSourceTypeException;
import com.azure.spring.data.gremlin.repository.support.GremlinEntityInformation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.tinkerpop.shaded.jackson.databind.MapperFeature;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.springframework.data.annotation.Id;
import org.springframework.lang.NonNull;
import org.springframework.util.ReflectionUtils;
public class GremlinUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.configure(MapperFeature.AUTO_DETECT_FIELDS, false);
}
public static ObjectMapper getObjectMapper() {
return MAPPER;
}
/**
* Create an instance for class type provided.
*
* @param type The class for the target type.
* @param <T> The class type.
* @return The created instance.
* @throws IllegalArgumentException If fails to instantiate.
*/
public static <T> T createInstance(@NonNull Class<T> type) {
final T instance;
try {
instance = type.newInstance();
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("can not access type constructor", e);
} catch (InstantiationException e) {
throw new IllegalArgumentException("failed to create instance of given type", e);
}
return instance;
}
/**
* Get the id field from a domain class.
*
* @param domainClass The target domain class.
* @param <T> The type of the id field.
* @return The {@link Field} of the id field.
* @throws GremlinIllegalConfigurationException If more than one field is configured with {@link GeneratedValue}
* annotation.
* @throws GremlinInvalidEntityIdFieldException If more than one {@link Id} annotated field are configured, no
* id field is configured, or the id field type is not allowed.
* @throws GremlinIllegalConfigurationException If field other than the id field is configured with {@link
* GeneratedValue} annotation.
*/
public static <T> Field getIdField(@NonNull Class<T> domainClass) {
final Field idField;
final List<Field> idFields = FieldUtils.getFieldsListWithAnnotation(domainClass, Id.class);
final List<Field> generatedValueFields =
FieldUtils.getFieldsListWithAnnotation(domainClass, GeneratedValue.class);
if (generatedValueFields.size() > 1) {
throw new GremlinIllegalConfigurationException("Only one field, the id field, can have the optional "
+ "@GeneratedValue annotation!");
}
if (idFields.isEmpty()) {
idField = ReflectionUtils.findField(domainClass, Constants.PROPERTY_ID);
} else if (idFields.size() == 1) {
idField = idFields.get(0);
} else {
throw new GremlinInvalidEntityIdFieldException("only one @Id field is allowed");
}
if (idField == null) {
throw new GremlinInvalidEntityIdFieldException("no field named id in class");
} else if (idField.getType() != String.class
&& idField.getType() != Long.class && idField.getType() != Integer.class) {
throw new GremlinInvalidEntityIdFieldException("the type of @Id/id field should be String/Integer/Long");
}
if (generatedValueFields.size() == 1 && !generatedValueFields.get(0).equals(idField)) {
throw new GremlinIllegalConfigurationException("Only the id field can have the optional "
+ "@GeneratedValue annotation!");
}
return idField;
}
/**
* Convert time object to milliseconds.
*
* @param time The time object.
* @return The milliseconds.
* @throws UnsupportedOperationException If the source type is not supported.
*/
public static long timeToMilliSeconds(@NonNull Object time) {
if (time instanceof Date) {
return ((Date) time).getTime();
} else {
throw new UnsupportedOperationException("Unsupported time type");
}
}
/**
* Convert object to equivalent long value.
*
* @param object The source object.
* @return The equivalent long value. If the source type is Date, it will convert to the milliseconds.
* @throws UnsupportedOperationException If the source type is not supported.
*/
public static long toPrimitiveLong(@NonNull Object object) {
if (object instanceof Date) {
return timeToMilliSeconds(object);
} else if (object instanceof Integer) {
return (long) (int) object;
} else if (object instanceof Long) {
return (long) object;
} else {
throw new UnsupportedOperationException("Unsupported object type to long");
}
}
public static <T> GremlinSource<T> toGremlinSource(@NonNull Class<T> domainClass) {
return new GremlinEntityInformation<>(domainClass).createGremlinSource();
}
public static List<List<String>> toParallelQueryList(@NonNull List<String> queries) {
final List<List<String>> parallelQueries = new ArrayList<>();
List<String> parallelQuery = new ArrayList<>();
for (final String query : queries) {
if (query.equals(Constants.GREMLIN_QUERY_BARRIER)) {
parallelQueries.add(parallelQuery);
parallelQuery = new ArrayList<>();
} else {
parallelQuery.add(query);
}
}
parallelQueries.add(parallelQuery);
return parallelQueries;
}
/**
* Convert a {@link String} represented class name to a Java {@link Class} type.
*
* @param className The class name.
* @return The {@link Class} type.
* @throws GremlinUnexpectedSourceTypeException If the class could not be found.
*/
public static Class<?> toEntityClass(@NonNull String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new GremlinUnexpectedSourceTypeException("failed to retrieve class: " + className, e);
}
}
}