From 5496876084d4cb811a4d0e8e22221268c5439174 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Tue, 25 Jan 2022 15:45:20 +0100 Subject: [PATCH 1/3] fix: split search enum in different files to improve java generation --- .../algoliasearch-core/com/algolia/JSON.java | 460 ++++++++++++++++++ .../model/BatchDictionaryEntriesRequest.java | 64 +-- .../com/algolia/model/DictionaryAction.java | 57 +++ .../com/algolia/model/DictionaryEntry.java | 64 +-- .../algolia/model/DictionaryEntryState.java | 57 +++ .../com/algolia/model/MultipleQueries.java | 64 +-- .../algolia/model/MultipleQueriesParams.java | 62 +-- .../model/MultipleQueriesStrategy.java | 57 +++ .../algolia/model/MultipleQueriesType.java | 57 +++ .../model/OneOfstringbuiltInOperation.java | 19 +- .../algolia/model/OperationIndexParams.java | 126 +---- .../com/algolia/model/OperationType.java | 56 +++ .../com/algolia/model/ScopeType.java | 56 +++ .../com/algolia/model/SynonymHit.java | 70 +-- .../com/algolia/model/SynonymType.java | 62 +++ .../com/algolia/search/SearchApi.java | 8 +- clients/algoliasearch-client-java-2/pom.xml | 11 +- .../model/batchDictionaryEntriesRequest.ts | 8 +- .../client-search/model/dictionaryAction.ts | 5 + .../client-search/model/dictionaryEntry.ts | 7 +- .../model/dictionaryEntryState.ts | 5 + .../client-search/model/multipleQueries.ts | 7 +- .../model/multipleQueriesParams.ts | 5 +- .../model/multipleQueriesStrategy.ts | 1 + .../model/multipleQueriesType.ts | 5 + .../model/operationIndexParams.ts | 14 +- .../client-search/model/operationType.ts | 5 + .../client-search/model/scopeType.ts | 1 + .../client-search/model/synonymHit.ts | 13 +- .../client-search/model/synonymType.ts | 10 + .../client-search/src/searchApi.ts | 13 +- specs/search/common/enums.yml | 29 ++ .../dictionaries/batchDictionaryEntries.yml | 4 +- .../SearchDictionaryEntriesResponse.yml | 5 +- .../paths/manage_indices/operationIndex.yml | 7 +- specs/search/paths/search/multipleQueries.yml | 8 +- .../paths/synonyms/common/parameters.yml | 18 +- .../search/paths/synonyms/common/schemas.yml | 9 +- templates/java/JSON.mustache | 451 ++++++++++++++++- templates/java/StringUtil.mustache | 69 --- .../java/libraries/okhttp-gson/pom.mustache | 11 +- 41 files changed, 1454 insertions(+), 606 deletions(-) create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryAction.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntryState.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesStrategy.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesType.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationType.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/ScopeType.java create mode 100644 clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymType.java create mode 100644 clients/algoliasearch-client-javascript/client-search/model/dictionaryAction.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/dictionaryEntryState.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/multipleQueriesStrategy.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/multipleQueriesType.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/operationType.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/scopeType.ts create mode 100644 clients/algoliasearch-client-javascript/client-search/model/synonymType.ts create mode 100644 specs/search/common/enums.yml delete mode 100644 templates/java/StringUtil.mustache diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/JSON.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/JSON.java index a9dc92333f..0bfbbc8762 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/JSON.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/JSON.java @@ -1,23 +1,51 @@ package com.algolia; +import com.google.gson.FieldNamingPolicy; +import com.google.gson.FieldNamingStrategy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.annotations.SerializedName; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.internal.Excluder; +import com.google.gson.internal.LinkedTreeMap; +import com.google.gson.internal.ObjectConstructor; +import com.google.gson.internal.Primitives; +import com.google.gson.internal.bind.MapTypeAdapterFactory; import com.google.gson.internal.bind.util.ISO8601Utils; +import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import io.gsonfire.GsonFireBuilder; import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Field; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.text.DateFormat; import java.text.ParseException; import java.text.ParsePosition; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; +import java.util.Collections; import java.util.Date; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; import okio.ByteString; public class JSON { @@ -29,6 +57,7 @@ public class JSON { private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter(); + private RetainFieldMapFactory mapAdapter = new RetainFieldMapFactory(); public static GsonBuilder createGson() { GsonFireBuilder fireBuilder = new GsonFireBuilder(); @@ -44,6 +73,7 @@ public JSON() { .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter) .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) .registerTypeAdapter(byte[].class, byteArrayAdapter) + .registerTypeAdapterFactory(mapAdapter) .create(); } @@ -351,3 +381,433 @@ public JSON setSqlDateFormat(DateFormat dateFormat) { return this; } } + +// https://stackoverflow.com/questions/21458468/gson-wont-properly-serialise-a-class-that-extends-hashmap +class RetainFieldMapFactory implements TypeAdapterFactory { + + FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; + ConstructorConstructor constructorConstructor = new ConstructorConstructor( + Collections.>emptyMap() + ); + MapTypeAdapterFactory defaultMapFactory = new MapTypeAdapterFactory( + constructorConstructor, + false + ); + ReflectiveFilterMapFieldFactory defaultObjectFactory = new ReflectiveFilterMapFieldFactory( + constructorConstructor, + fieldNamingPolicy, + Excluder.DEFAULT + ); + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + final TypeAdapter mapAdapter = defaultMapFactory.create(gson, type); + if (mapAdapter != null) { + return (TypeAdapter) new RetainFieldMapAdapter( + mapAdapter, + defaultObjectFactory.create(gson, type) + ); + } + return mapAdapter; + } + + class RetainFieldMapAdapter extends TypeAdapter> { + + TypeAdapter> mapAdapter; + ReflectiveTypeAdapterFactory.Adapter> objectAdapter; + + RetainFieldMapAdapter( + TypeAdapter mapAdapter, + ReflectiveTypeAdapterFactory.Adapter objectAdapter + ) { + this.mapAdapter = mapAdapter; + this.objectAdapter = objectAdapter; + } + + @Override + public void write(final JsonWriter out, Map value) + throws IOException { + if (value == null) { + out.nullValue(); + return; + } + // 1.write object + StringWriter sw = new StringWriter(); + objectAdapter.write(new JsonWriter(sw), value); + + // 2.convert object to a map + Map objectMap = mapAdapter.fromJson(sw.toString()); + + // 3.overwrite fields in object to a copy map + value = new LinkedHashMap(value); + value.putAll(objectMap); + + // 4.write the copy map + mapAdapter.write(out, value); + } + + @Override + public Map read(JsonReader in) throws IOException { + // 1.create map, all key-value retain in map + Map map = mapAdapter.read(in); + + // 2.create object from created map + Map object = objectAdapter.fromJsonTree( + mapAdapter.toJsonTree(map) + ); + + // 3.remove fields in object from map + for (String field : objectAdapter.boundFields.keySet()) { + map.remove(field); + } + // 4.put map to object + object.putAll(map); + return object; + } + } + + static class ReflectiveFilterMapFieldFactory + extends ReflectiveTypeAdapterFactory { + + public ReflectiveFilterMapFieldFactory( + ConstructorConstructor constructorConstructor, + FieldNamingStrategy fieldNamingPolicy, + Excluder excluder + ) { + super(constructorConstructor, fieldNamingPolicy, excluder); + } + + @Override + protected boolean shouldFindFieldInClass( + Class willFindClass, + Class originalRaw + ) { + Class[] endClasses = new Class[] { + Object.class, + HashMap.class, + LinkedHashMap.class, + LinkedTreeMap.class, + Hashtable.class, + TreeMap.class, + ConcurrentHashMap.class, + IdentityHashMap.class, + WeakHashMap.class, + EnumMap.class, + }; + for (Class c : endClasses) { + if (willFindClass == c) return false; + } + + return super.shouldFindFieldInClass(willFindClass, originalRaw); + } + } + + /** + * below code copy from {@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory} (little + * modify, in source this class is final) Type adapter that reflects over the fields and methods + * of a class. + */ + static class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { + + private final ConstructorConstructor constructorConstructor; + private final FieldNamingStrategy fieldNamingPolicy; + private final Excluder excluder; + + public ReflectiveTypeAdapterFactory( + ConstructorConstructor constructorConstructor, + FieldNamingStrategy fieldNamingPolicy, + Excluder excluder + ) { + this.constructorConstructor = constructorConstructor; + this.fieldNamingPolicy = fieldNamingPolicy; + this.excluder = excluder; + } + + public boolean excludeField(Field f, boolean serialize) { + return ( + !excluder.excludeClass(f.getType(), serialize) && + !excluder.excludeField(f, serialize) + ); + } + + private String getFieldName(Field f) { + SerializedName serializedName = f.getAnnotation(SerializedName.class); + return serializedName == null + ? fieldNamingPolicy.translateName(f) + : serializedName.value(); + } + + public Adapter create(Gson gson, final TypeToken type) { + Class raw = type.getRawType(); + + if (!Object.class.isAssignableFrom(raw)) { + return null; // it's a primitive! + } + + ObjectConstructor constructor = constructorConstructor.get(type); + return new Adapter(constructor, getBoundFields(gson, type, raw)); + } + + private ReflectiveTypeAdapterFactory.BoundField createBoundField( + final Gson context, + final Field field, + final String name, + final TypeToken fieldType, + boolean serialize, + boolean deserialize + ) { + final boolean isPrimitive = Primitives.isPrimitive( + fieldType.getRawType() + ); + + // special casing primitives here saves ~5% on Android... + return new ReflectiveTypeAdapterFactory.BoundField( + name, + serialize, + deserialize + ) { + final TypeAdapter typeAdapter = context.getAdapter(fieldType); + + @SuppressWarnings({ "unchecked", "rawtypes" }) // the type adapter and field type always agree + @Override + void write(JsonWriter writer, Object value) + throws IOException, IllegalAccessException { + Object fieldValue = field.get(value); + TypeAdapter t = new TypeAdapterRuntimeTypeWrapper( + context, + this.typeAdapter, + fieldType.getType() + ); + t.write(writer, fieldValue); + } + + @Override + void read(JsonReader reader, Object value) + throws IOException, IllegalAccessException { + Object fieldValue = typeAdapter.read(reader); + if (fieldValue != null || !isPrimitive) { + field.set(value, fieldValue); + } + } + }; + } + + private Map getBoundFields( + Gson context, + TypeToken type, + Class raw + ) { + Map result = new LinkedHashMap(); + if (raw.isInterface()) { + return result; + } + + Type declaredType = type.getType(); + Class originalRaw = type.getRawType(); + while (shouldFindFieldInClass(raw, originalRaw)) { + Field[] fields = raw.getDeclaredFields(); + for (Field field : fields) { + boolean serialize = excludeField(field, true); + boolean deserialize = excludeField(field, false); + if (!serialize && !deserialize) { + continue; + } + field.setAccessible(true); + Type fieldType = $Gson$Types.resolve( + type.getType(), + raw, + field.getGenericType() + ); + BoundField boundField = createBoundField( + context, + field, + getFieldName(field), + TypeToken.get(fieldType), + serialize, + deserialize + ); + BoundField previous = result.put(boundField.name, boundField); + if (previous != null) { + throw new IllegalArgumentException( + declaredType + + " declares multiple JSON fields named " + + previous.name + ); + } + } + type = + TypeToken.get( + $Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()) + ); + raw = type.getRawType(); + } + return result; + } + + protected boolean shouldFindFieldInClass( + Class willFindClass, + Class originalRaw + ) { + return willFindClass != Object.class; + } + + abstract static class BoundField { + + final String name; + final boolean serialized; + final boolean deserialized; + + protected BoundField( + String name, + boolean serialized, + boolean deserialized + ) { + this.name = name; + this.serialized = serialized; + this.deserialized = deserialized; + } + + abstract void write(JsonWriter writer, Object value) + throws IOException, IllegalAccessException; + + abstract void read(JsonReader reader, Object value) + throws IOException, IllegalAccessException; + } + + public static final class Adapter extends TypeAdapter { + + private final ObjectConstructor constructor; + private final Map boundFields; + + private Adapter( + ObjectConstructor constructor, + Map boundFields + ) { + this.constructor = constructor; + this.boundFields = boundFields; + } + + @Override + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + T instance = constructor.construct(); + + try { + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + BoundField field = boundFields.get(name); + if (field == null || !field.deserialized) { + in.skipValue(); + } else { + field.read(in, instance); + } + } + } catch (IllegalStateException e) { + throw new JsonSyntaxException(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + in.endObject(); + return instance; + } + + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + + out.beginObject(); + try { + for (BoundField boundField : boundFields.values()) { + if (boundField.serialized) { + out.name(boundField.name); + boundField.write(out, value); + } + } + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + out.endObject(); + } + } + } + + static class TypeAdapterRuntimeTypeWrapper extends TypeAdapter { + + private final Gson context; + private final TypeAdapter delegate; + private final Type type; + + TypeAdapterRuntimeTypeWrapper( + Gson context, + TypeAdapter delegate, + Type type + ) { + this.context = context; + this.delegate = delegate; + this.type = type; + } + + @Override + public T read(JsonReader in) throws IOException { + return delegate.read(in); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void write(JsonWriter out, T value) throws IOException { + // Order of preference for choosing type adapters + // First preference: a type adapter registered for the runtime type + // Second preference: a type adapter registered for the declared type + // Third preference: reflective type adapter for the runtime type (if it is a + // sub class of the declared type) + // Fourth preference: reflective type adapter for the declared type + + TypeAdapter chosen = delegate; + Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value); + if (runtimeType != type) { + TypeAdapter runtimeTypeAdapter = context.getAdapter( + TypeToken.get(runtimeType) + ); + if ( + !(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter) + ) { + // The user registered a type adapter for the runtime type, so we will use that + chosen = runtimeTypeAdapter; + } else if ( + !(delegate instanceof ReflectiveTypeAdapterFactory.Adapter) + ) { + // The user registered a type adapter for Base class, so we prefer it over the + // reflective type adapter for the runtime type + chosen = delegate; + } else { + // Use the type adapter for runtime type + chosen = runtimeTypeAdapter; + } + } + chosen.write(out, value); + } + + /** Finds a compatible runtime type if it is more specific */ + private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) { + if ( + value != null && + ( + type == Object.class || + type instanceof TypeVariable || + type instanceof Class + ) + ) { + type = value.getClass(); + } + return type; + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/BatchDictionaryEntriesRequest.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/BatchDictionaryEntriesRequest.java index 17a3d3e91c..d356b71b3c 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/BatchDictionaryEntriesRequest.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/BatchDictionaryEntriesRequest.java @@ -1,87 +1,33 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.Objects; /** BatchDictionaryEntriesRequest */ public class BatchDictionaryEntriesRequest { - /** Actions to perform. */ - @JsonAdapter(ActionEnum.Adapter.class) - public enum ActionEnum { - ADDENTRY("addEntry"), - - DELETEENTRY("deleteEntry"); - - private String value; - - ActionEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static ActionEnum fromValue(String value) { - for (ActionEnum b : ActionEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final ActionEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public ActionEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return ActionEnum.fromValue(value); - } - } - } - @SerializedName("action") - private ActionEnum action; + private DictionaryAction action; @SerializedName("body") private DictionaryEntry body; - public BatchDictionaryEntriesRequest action(ActionEnum action) { + public BatchDictionaryEntriesRequest action(DictionaryAction action) { this.action = action; return this; } /** - * Actions to perform. + * Get action * * @return action */ @javax.annotation.Nonnull - public ActionEnum getAction() { + public DictionaryAction getAction() { return action; } - public void setAction(ActionEnum action) { + public void setAction(DictionaryAction action) { this.action = action; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryAction.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryAction.java new file mode 100644 index 0000000000..e5de49834b --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryAction.java @@ -0,0 +1,57 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Actions to perform. */ +@JsonAdapter(DictionaryAction.Adapter.class) +public enum DictionaryAction { + ADDENTRY("addEntry"), + + DELETEENTRY("deleteEntry"); + + private String value; + + DictionaryAction(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static DictionaryAction fromValue(String value) { + for (DictionaryAction b : DictionaryAction.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final DictionaryAction enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public DictionaryAction read(final JsonReader jsonReader) + throws IOException { + String value = jsonReader.nextString(); + return DictionaryAction.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntry.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntry.java index 767a555c79..d0b4bb179f 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntry.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntry.java @@ -1,11 +1,6 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -29,57 +24,8 @@ public class DictionaryEntry extends HashMap { @SerializedName("decomposition") private List decomposition = null; - /** The state of the dictionary entry. */ - @JsonAdapter(StateEnum.Adapter.class) - public enum StateEnum { - ENABLED("enabled"), - - DISABLED("disabled"); - - private String value; - - StateEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static StateEnum fromValue(String value) { - for (StateEnum b : StateEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final StateEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public StateEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return StateEnum.fromValue(value); - } - } - } - @SerializedName("state") - private StateEnum state = StateEnum.ENABLED; + private DictionaryEntryState state = DictionaryEntryState.ENABLED; public DictionaryEntry objectID(String objectID) { this.objectID = objectID; @@ -192,22 +138,22 @@ public void setDecomposition(List decomposition) { this.decomposition = decomposition; } - public DictionaryEntry state(StateEnum state) { + public DictionaryEntry state(DictionaryEntryState state) { this.state = state; return this; } /** - * The state of the dictionary entry. + * Get state * * @return state */ @javax.annotation.Nullable - public StateEnum getState() { + public DictionaryEntryState getState() { return state; } - public void setState(StateEnum state) { + public void setState(DictionaryEntryState state) { this.state = state; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntryState.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntryState.java new file mode 100644 index 0000000000..99d55c2bce --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/DictionaryEntryState.java @@ -0,0 +1,57 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** The state of the dictionary entry. */ +@JsonAdapter(DictionaryEntryState.Adapter.class) +public enum DictionaryEntryState { + ENABLED("enabled"), + + DISABLED("disabled"); + + private String value; + + DictionaryEntryState(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static DictionaryEntryState fromValue(String value) { + for (DictionaryEntryState b : DictionaryEntryState.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final DictionaryEntryState enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public DictionaryEntryState read(final JsonReader jsonReader) + throws IOException { + String value = jsonReader.nextString(); + return DictionaryEntryState.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueries.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueries.java index b4cfd6b433..a0c2fe6b9c 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueries.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueries.java @@ -1,11 +1,6 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.Objects; /** MultipleQueries */ @@ -17,57 +12,8 @@ public class MultipleQueries { @SerializedName("query") private String query = ""; - /** Perform a search query with `default`, will search for facet values if `facet` is given. */ - @JsonAdapter(TypeEnum.Adapter.class) - public enum TypeEnum { - DEFAULT("default"), - - FACET("facet"); - - private String value; - - TypeEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static TypeEnum fromValue(String value) { - for (TypeEnum b : TypeEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final TypeEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public TypeEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return TypeEnum.fromValue(value); - } - } - } - @SerializedName("type") - private TypeEnum type = TypeEnum.DEFAULT; + private MultipleQueriesType type = MultipleQueriesType.DEFAULT; @SerializedName("facet") private String facet; @@ -113,22 +59,22 @@ public void setQuery(String query) { this.query = query; } - public MultipleQueries type(TypeEnum type) { + public MultipleQueries type(MultipleQueriesType type) { this.type = type; return this; } /** - * Perform a search query with `default`, will search for facet values if `facet` is given. + * Get type * * @return type */ @javax.annotation.Nullable - public TypeEnum getType() { + public MultipleQueriesType getType() { return type; } - public void setType(TypeEnum type) { + public void setType(MultipleQueriesType type) { this.type = type; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesParams.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesParams.java index 8279ff9d02..952256492d 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesParams.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesParams.java @@ -1,11 +1,6 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -16,57 +11,8 @@ public class MultipleQueriesParams { @SerializedName("requests") private List requests = new ArrayList<>(); - /** Gets or Sets strategy */ - @JsonAdapter(StrategyEnum.Adapter.class) - public enum StrategyEnum { - NONE("none"), - - STOPIFENOUGHMATCHES("stopIfEnoughMatches"); - - private String value; - - StrategyEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static StrategyEnum fromValue(String value) { - for (StrategyEnum b : StrategyEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final StrategyEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public StrategyEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return StrategyEnum.fromValue(value); - } - } - } - @SerializedName("strategy") - private StrategyEnum strategy; + private MultipleQueriesStrategy strategy; public MultipleQueriesParams requests(List requests) { this.requests = requests; @@ -92,7 +38,7 @@ public void setRequests(List requests) { this.requests = requests; } - public MultipleQueriesParams strategy(StrategyEnum strategy) { + public MultipleQueriesParams strategy(MultipleQueriesStrategy strategy) { this.strategy = strategy; return this; } @@ -103,11 +49,11 @@ public MultipleQueriesParams strategy(StrategyEnum strategy) { * @return strategy */ @javax.annotation.Nullable - public StrategyEnum getStrategy() { + public MultipleQueriesStrategy getStrategy() { return strategy; } - public void setStrategy(StrategyEnum strategy) { + public void setStrategy(MultipleQueriesStrategy strategy) { this.strategy = strategy; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesStrategy.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesStrategy.java new file mode 100644 index 0000000000..0fda9238b4 --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesStrategy.java @@ -0,0 +1,57 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Gets or Sets multipleQueriesStrategy */ +@JsonAdapter(MultipleQueriesStrategy.Adapter.class) +public enum MultipleQueriesStrategy { + NONE("none"), + + STOPIFENOUGHMATCHES("stopIfEnoughMatches"); + + private String value; + + MultipleQueriesStrategy(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static MultipleQueriesStrategy fromValue(String value) { + for (MultipleQueriesStrategy b : MultipleQueriesStrategy.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final MultipleQueriesStrategy enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public MultipleQueriesStrategy read(final JsonReader jsonReader) + throws IOException { + String value = jsonReader.nextString(); + return MultipleQueriesStrategy.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesType.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesType.java new file mode 100644 index 0000000000..266c455b7c --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/MultipleQueriesType.java @@ -0,0 +1,57 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Perform a search query with `default`, will search for facet values if `facet` is given. */ +@JsonAdapter(MultipleQueriesType.Adapter.class) +public enum MultipleQueriesType { + DEFAULT("default"), + + FACET("facet"); + + private String value; + + MultipleQueriesType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static MultipleQueriesType fromValue(String value) { + for (MultipleQueriesType b : MultipleQueriesType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final MultipleQueriesType enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public MultipleQueriesType read(final JsonReader jsonReader) + throws IOException { + String value = jsonReader.nextString(); + return MultipleQueriesType.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java index c833c61636..8ac01fc739 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java @@ -1,3 +1,20 @@ package com.algolia.model; -public class OneOfstringbuiltInOperation {} +import com.google.gson.annotations.SerializedName; + +public class OneOfstringbuiltInOperation { + + @SerializedName("_operation") + private String _operation; + + @SerializedName("value") + private String value; + + public void set_operation(String op) { + _operation = op; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationIndexParams.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationIndexParams.java index 32c97d1262..a048fc5fc3 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationIndexParams.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationIndexParams.java @@ -1,11 +1,6 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -13,132 +8,31 @@ /** OperationIndexParams */ public class OperationIndexParams { - /** Type of operation to perform (move or copy). */ - @JsonAdapter(OperationEnum.Adapter.class) - public enum OperationEnum { - MOVE("move"), - - COPY("copy"); - - private String value; - - OperationEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static OperationEnum fromValue(String value) { - for (OperationEnum b : OperationEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final OperationEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public OperationEnum read(final JsonReader jsonReader) - throws IOException { - String value = jsonReader.nextString(); - return OperationEnum.fromValue(value); - } - } - } - @SerializedName("operation") - private OperationEnum operation; + private OperationType operation; @SerializedName("destination") private String destination; - /** Gets or Sets scope */ - @JsonAdapter(ScopeEnum.Adapter.class) - public enum ScopeEnum { - SETTINGS("settings"), - - SYNONYMS("synonyms"), - - RULES("rules"); - - private String value; - - ScopeEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static ScopeEnum fromValue(String value) { - for (ScopeEnum b : ScopeEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final ScopeEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public ScopeEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return ScopeEnum.fromValue(value); - } - } - } - @SerializedName("scope") - private List scope = null; + private List scope = null; - public OperationIndexParams operation(OperationEnum operation) { + public OperationIndexParams operation(OperationType operation) { this.operation = operation; return this; } /** - * Type of operation to perform (move or copy). + * Get operation * * @return operation */ @javax.annotation.Nonnull - public OperationEnum getOperation() { + public OperationType getOperation() { return operation; } - public void setOperation(OperationEnum operation) { + public void setOperation(OperationType operation) { this.operation = operation; } @@ -161,12 +55,12 @@ public void setDestination(String destination) { this.destination = destination; } - public OperationIndexParams scope(List scope) { + public OperationIndexParams scope(List scope) { this.scope = scope; return this; } - public OperationIndexParams addScopeItem(ScopeEnum scopeItem) { + public OperationIndexParams addScopeItem(ScopeType scopeItem) { if (this.scope == null) { this.scope = new ArrayList<>(); } @@ -181,11 +75,11 @@ public OperationIndexParams addScopeItem(ScopeEnum scopeItem) { * @return scope */ @javax.annotation.Nullable - public List getScope() { + public List getScope() { return scope; } - public void setScope(List scope) { + public void setScope(List scope) { this.scope = scope; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationType.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationType.java new file mode 100644 index 0000000000..05336d71f5 --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OperationType.java @@ -0,0 +1,56 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Type of operation to perform (move or copy). */ +@JsonAdapter(OperationType.Adapter.class) +public enum OperationType { + MOVE("move"), + + COPY("copy"); + + private String value; + + OperationType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static OperationType fromValue(String value) { + for (OperationType b : OperationType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final OperationType enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public OperationType read(final JsonReader jsonReader) throws IOException { + String value = jsonReader.nextString(); + return OperationType.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/ScopeType.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/ScopeType.java new file mode 100644 index 0000000000..cd9de1f61c --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/ScopeType.java @@ -0,0 +1,56 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Gets or Sets scopeType */ +@JsonAdapter(ScopeType.Adapter.class) +public enum ScopeType { + SETTINGS("settings"), + + SYNONYMS("synonyms"), + + RULES("rules"); + + private String value; + + ScopeType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static ScopeType fromValue(String value) { + for (ScopeType b : ScopeType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write(final JsonWriter jsonWriter, final ScopeType enumeration) + throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public ScopeType read(final JsonReader jsonReader) throws IOException { + String value = jsonReader.nextString(); + return ScopeType.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymHit.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymHit.java index cde0e82774..ffa9eaeeb1 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymHit.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymHit.java @@ -1,11 +1,6 @@ package com.algolia.model; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -16,63 +11,8 @@ public class SynonymHit { @SerializedName("objectID") private String objectID; - /** Type of the synonym object. */ - @JsonAdapter(TypeEnum.Adapter.class) - public enum TypeEnum { - SYNONYM("synonym"), - - ONEWAYSYNONYM("onewaysynonym"), - - ALTCORRECTION1("altcorrection1"), - - ALTCORRECTION2("altcorrection2"), - - PLACEHOLDER("placeholder"); - - private String value; - - TypeEnum(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static TypeEnum fromValue(String value) { - for (TypeEnum b : TypeEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } - - public static class Adapter extends TypeAdapter { - - @Override - public void write( - final JsonWriter jsonWriter, - final TypeEnum enumeration - ) throws IOException { - jsonWriter.value(enumeration.getValue()); - } - - @Override - public TypeEnum read(final JsonReader jsonReader) throws IOException { - String value = jsonReader.nextString(); - return TypeEnum.fromValue(value); - } - } - } - @SerializedName("type") - private TypeEnum type; + private SynonymType type; @SerializedName("synonyms") private List synonyms = null; @@ -114,22 +54,22 @@ public void setObjectID(String objectID) { this.objectID = objectID; } - public SynonymHit type(TypeEnum type) { + public SynonymHit type(SynonymType type) { this.type = type; return this; } /** - * Type of the synonym object. + * Get type * * @return type */ @javax.annotation.Nonnull - public TypeEnum getType() { + public SynonymType getType() { return type; } - public void setType(TypeEnum type) { + public void setType(SynonymType type) { this.type = type; } diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymType.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymType.java new file mode 100644 index 0000000000..cd57b50d7a --- /dev/null +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/SynonymType.java @@ -0,0 +1,62 @@ +package com.algolia.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Type of the synonym object. */ +@JsonAdapter(SynonymType.Adapter.class) +public enum SynonymType { + SYNONYM("synonym"), + + ONEWAYSYNONYM("onewaysynonym"), + + ALTCORRECTION1("altcorrection1"), + + ALTCORRECTION2("altcorrection2"), + + PLACEHOLDER("placeholder"); + + private String value; + + SynonymType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static SynonymType fromValue(String value) { + for (SynonymType b : SynonymType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + + @Override + public void write( + final JsonWriter jsonWriter, + final SynonymType enumeration + ) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public SynonymType read(final JsonReader jsonReader) throws IOException { + String value = jsonReader.nextString(); + return SynonymType.fromValue(value); + } + } +} diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/search/SearchApi.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/search/SearchApi.java index ba9e2efd10..5c6167035f 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/search/SearchApi.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/search/SearchApi.java @@ -5522,7 +5522,7 @@ public Call searchRulesAsync( private Call searchSynonymsCall( String indexName, String query, - String type, + SynonymType type, Integer page, Integer hitsPerPage, final ApiCallback _callback @@ -5571,7 +5571,7 @@ private Call searchSynonymsCall( private Call searchSynonymsValidateBeforeCall( String indexName, String query, - String type, + SynonymType type, Integer page, Integer hitsPerPage, final ApiCallback _callback @@ -5610,7 +5610,7 @@ private Call searchSynonymsValidateBeforeCall( public SearchSynonymsResponse searchSynonyms( String indexName, String query, - String type, + SynonymType type, Integer page, Integer hitsPerPage ) throws ApiException { @@ -5653,7 +5653,7 @@ public SearchSynonymsResponse searchSynonyms(String indexName) public Call searchSynonymsAsync( String indexName, String query, - String type, + SynonymType type, Integer page, Integer hitsPerPage, final ApiCallback _callback diff --git a/clients/algoliasearch-client-java-2/pom.xml b/clients/algoliasearch-client-java-2/pom.xml index f1d434e47f..609749ff8d 100644 --- a/clients/algoliasearch-client-java-2/pom.xml +++ b/clients/algoliasearch-client-java-2/pom.xml @@ -36,7 +36,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.9.0 true 128m @@ -170,12 +170,6 @@ gson-fire ${gson-fire-version} - - jakarta.annotation - jakarta.annotation-api - ${jakarta-annotation-version} - provided - 1.8 @@ -183,8 +177,7 @@ ${java.version} 1.8.5 4.9.1 - 2.8.6 - 1.3.5 + 2.8.9 UTF-8 diff --git a/clients/algoliasearch-client-javascript/client-search/model/batchDictionaryEntriesRequest.ts b/clients/algoliasearch-client-javascript/client-search/model/batchDictionaryEntriesRequest.ts index 86c96f303d..49ec3569cd 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/batchDictionaryEntriesRequest.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/batchDictionaryEntriesRequest.ts @@ -1,11 +1,7 @@ +import type { DictionaryAction } from './dictionaryAction'; import type { DictionaryEntry } from './dictionaryEntry'; export type BatchDictionaryEntriesRequest = { - /** - * Actions to perform. - */ - action: BatchDictionaryEntriesRequestAction; + action: DictionaryAction; body: DictionaryEntry; }; - -export type BatchDictionaryEntriesRequestAction = 'addEntry' | 'deleteEntry'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/dictionaryAction.ts b/clients/algoliasearch-client-javascript/client-search/model/dictionaryAction.ts new file mode 100644 index 0000000000..cd9ad65e77 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/dictionaryAction.ts @@ -0,0 +1,5 @@ +/** + * Actions to perform. + */ + +export type DictionaryAction = 'addEntry' | 'deleteEntry'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntry.ts b/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntry.ts index dd8bd81417..4fd672ddbe 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntry.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntry.ts @@ -1,3 +1,5 @@ +import type { DictionaryEntryState } from './dictionaryEntryState'; + /** * A dictionary entry. */ @@ -22,10 +24,5 @@ export type DictionaryEntry = { * A decomposition of the word of the dictionary entry. */ decomposition?: string[]; - /** - * The state of the dictionary entry. - */ state?: DictionaryEntryState; }; - -export type DictionaryEntryState = 'disabled' | 'enabled'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntryState.ts b/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntryState.ts new file mode 100644 index 0000000000..676ad575c2 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/dictionaryEntryState.ts @@ -0,0 +1,5 @@ +/** + * The state of the dictionary entry. + */ + +export type DictionaryEntryState = 'disabled' | 'enabled'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/multipleQueries.ts b/clients/algoliasearch-client-javascript/client-search/model/multipleQueries.ts index 42931f8578..1096b0c8fa 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/multipleQueries.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/multipleQueries.ts @@ -1,3 +1,5 @@ +import type { MultipleQueriesType } from './multipleQueriesType'; + export type MultipleQueries = { /** * The Algolia index name. @@ -7,9 +9,6 @@ export type MultipleQueries = { * The text to search in the index. */ query?: string; - /** - * Perform a search query with `default`, will search for facet values if `facet` is given. - */ type?: MultipleQueriesType; /** * The `facet` name. @@ -20,5 +19,3 @@ export type MultipleQueries = { */ params?: string; }; - -export type MultipleQueriesType = 'default' | 'facet'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesParams.ts b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesParams.ts index dbbd88f4b2..eef22ed29f 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesParams.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesParams.ts @@ -1,8 +1,7 @@ import type { MultipleQueries } from './multipleQueries'; +import type { MultipleQueriesStrategy } from './multipleQueriesStrategy'; export type MultipleQueriesParams = { requests: MultipleQueries[]; - strategy?: MultipleQueriesParamsStrategy; + strategy?: MultipleQueriesStrategy; }; - -export type MultipleQueriesParamsStrategy = 'none' | 'stopIfEnoughMatches'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesStrategy.ts b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesStrategy.ts new file mode 100644 index 0000000000..5090359e8e --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesStrategy.ts @@ -0,0 +1 @@ +export type MultipleQueriesStrategy = 'none' | 'stopIfEnoughMatches'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesType.ts b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesType.ts new file mode 100644 index 0000000000..cd27b91929 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/multipleQueriesType.ts @@ -0,0 +1,5 @@ +/** + * Perform a search query with `default`, will search for facet values if `facet` is given. + */ + +export type MultipleQueriesType = 'default' | 'facet'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/operationIndexParams.ts b/clients/algoliasearch-client-javascript/client-search/model/operationIndexParams.ts index ca5bc708bf..90da3e1e22 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/operationIndexParams.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/operationIndexParams.ts @@ -1,8 +1,8 @@ +import type { OperationType } from './operationType'; +import type { ScopeType } from './scopeType'; + export type OperationIndexParams = { - /** - * Type of operation to perform (move or copy). - */ - operation: OperationIndexParamsOperation; + operation: OperationType; /** * The Algolia index name. */ @@ -10,9 +10,5 @@ export type OperationIndexParams = { /** * Scope of the data to copy. When absent, a full copy is performed. When present, only the selected scopes are copied. */ - scope?: OperationIndexParamsScope[]; + scope?: ScopeType[]; }; - -export type OperationIndexParamsOperation = 'copy' | 'move'; - -export type OperationIndexParamsScope = 'rules' | 'settings' | 'synonyms'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/operationType.ts b/clients/algoliasearch-client-javascript/client-search/model/operationType.ts new file mode 100644 index 0000000000..9d7bab7040 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/operationType.ts @@ -0,0 +1,5 @@ +/** + * Type of operation to perform (move or copy). + */ + +export type OperationType = 'copy' | 'move'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/scopeType.ts b/clients/algoliasearch-client-javascript/client-search/model/scopeType.ts new file mode 100644 index 0000000000..ea19044f2d --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/scopeType.ts @@ -0,0 +1 @@ +export type ScopeType = 'rules' | 'settings' | 'synonyms'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts b/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts index becd50b026..2bbe5dbe11 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts @@ -1,4 +1,5 @@ import type { SynonymHitHighlightResult } from './synonymHitHighlightResult'; +import type { SynonymType } from './synonymType'; /** * Synonym object. @@ -8,10 +9,7 @@ export type SynonymHit = { * Unique identifier of the synonym object to be created or updated. */ objectID: string; - /** - * Type of the synonym object. - */ - type: SynonymHitType; + type: SynonymType; /** * Words or phrases to be considered equivalent. */ @@ -38,10 +36,3 @@ export type SynonymHit = { replacements?: string[]; _highlightResult?: SynonymHitHighlightResult; }; - -export type SynonymHitType = - | 'altcorrection1' - | 'altcorrection2' - | 'onewaysynonym' - | 'placeholder' - | 'synonym'; diff --git a/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts b/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts new file mode 100644 index 0000000000..f7a6b44452 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts @@ -0,0 +1,10 @@ +/** + * Type of the synonym object. + */ + +export type SynonymType = + | 'altcorrection1' + | 'altcorrection2' + | 'onewaysynonym' + | 'placeholder' + | 'synonym'; diff --git a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts index 6fc26cd3e9..f426532c36 100644 --- a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts +++ b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts @@ -57,6 +57,7 @@ import type { SearchUserIdsParams } from '../model/searchUserIdsParams'; import type { SearchUserIdsResponse } from '../model/searchUserIdsResponse'; import type { Source } from '../model/source'; import type { SynonymHit } from '../model/synonymHit'; +import type { SynonymType } from '../model/synonymType'; import type { UpdateApiKeyResponse } from '../model/updateApiKeyResponse'; import type { UpdatedAtResponse } from '../model/updatedAtResponse'; import type { UpdatedAtWithObjectIdResponse } from '../model/updatedAtWithObjectIdResponse'; @@ -1962,11 +1963,6 @@ export class SearchApi { 'Parameter `synonymHit.objectID` is required when calling `saveSynonym`.' ); } - if (!synonymHit.type) { - throw new Error( - 'Parameter `synonymHit.type` is required when calling `saveSynonym`.' - ); - } if (forwardToReplicas !== undefined) { queryParameters.forwardToReplicas = forwardToReplicas.toString(); @@ -2897,12 +2893,7 @@ export type SearchSynonymsProps = { /** * Only search for specific types of synonyms. */ - type?: - | 'altcorrection1' - | 'altcorrection2' - | 'onewaysynonym' - | 'placeholder' - | 'synonym'; + type?: SynonymType; /** * Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). */ diff --git a/specs/search/common/enums.yml b/specs/search/common/enums.yml new file mode 100644 index 0000000000..c90345a657 --- /dev/null +++ b/specs/search/common/enums.yml @@ -0,0 +1,29 @@ +multipleQueriesType: + type: string + enum: [default, facet] + default: default + description: Perform a search query with `default`, will search for facet values if `facet` is given. + +multipleQueriesStrategy: + type: string + enum: [none, stopIfEnoughMatches] + +operationType: + type: string + enum: [move, copy] + description: Type of operation to perform (move or copy). + +scopeType: + type: string + enum: [settings, synonyms, rules] + +dictionaryAction: + type: string + enum: [addEntry, deleteEntry] + description: Actions to perform. + +dictionaryEntryState: + type: string + enum: [enabled, disabled] + default: enabled + description: The state of the dictionary entry. diff --git a/specs/search/paths/dictionaries/batchDictionaryEntries.yml b/specs/search/paths/dictionaries/batchDictionaryEntries.yml index d6b6fa8b42..d67a3d7070 100644 --- a/specs/search/paths/dictionaries/batchDictionaryEntries.yml +++ b/specs/search/paths/dictionaries/batchDictionaryEntries.yml @@ -34,9 +34,7 @@ post: - body properties: action: - description: Actions to perform. - type: string - enum: [addEntry, deleteEntry] + $ref: '../../common/enums.yml#/dictionaryAction' body: $ref: 'common/schemas/SearchDictionaryEntriesResponse.yml#/dictionaryEntry' responses: diff --git a/specs/search/paths/dictionaries/common/schemas/SearchDictionaryEntriesResponse.yml b/specs/search/paths/dictionaries/common/schemas/SearchDictionaryEntriesResponse.yml index 682e13a1ba..6f9b89f29a 100644 --- a/specs/search/paths/dictionaries/common/schemas/SearchDictionaryEntriesResponse.yml +++ b/specs/search/paths/dictionaries/common/schemas/SearchDictionaryEntriesResponse.yml @@ -41,7 +41,4 @@ dictionaryEntry: items: type: string state: - description: The state of the dictionary entry. - type: string - enum: [enabled, disabled] - default: enabled + $ref: '../../../../common/enums.yml#/dictionaryEntryState' diff --git a/specs/search/paths/manage_indices/operationIndex.yml b/specs/search/paths/manage_indices/operationIndex.yml index c75539ca6f..44d92ba584 100644 --- a/specs/search/paths/manage_indices/operationIndex.yml +++ b/specs/search/paths/manage_indices/operationIndex.yml @@ -16,16 +16,13 @@ post: additionalProperties: false properties: operation: - type: string - enum: [move, copy] - description: Type of operation to perform (move or copy). + $ref: '../../common/enums.yml#/operationType' destination: $ref: '../../../common/parameters.yml#/indexName' scope: type: array items: - type: string - enum: [settings, synonyms, rules] + $ref: '../../common/enums.yml#/scopeType' description: Scope of the data to copy. When absent, a full copy is performed. When present, only the selected scopes are copied. required: - operation diff --git a/specs/search/paths/search/multipleQueries.yml b/specs/search/paths/search/multipleQueries.yml index b008b5c469..1d2d140d74 100644 --- a/specs/search/paths/search/multipleQueries.yml +++ b/specs/search/paths/search/multipleQueries.yml @@ -26,10 +26,7 @@ post: query: $ref: '../../../common/schemas/SearchParams.yml#/query' type: - type: string - enum: [default, facet] - default: default - description: Perform a search query with `default`, will search for facet values if `facet` is given. + $ref: '../../common/enums.yml#/multipleQueriesType' facet: type: string description: The `facet` name. @@ -39,8 +36,7 @@ post: required: - indexName strategy: - type: string - enum: [none, stopIfEnoughMatches] + $ref: '../../common/enums.yml#/multipleQueriesStrategy' required: - requests responses: diff --git a/specs/search/paths/synonyms/common/parameters.yml b/specs/search/paths/synonyms/common/parameters.yml index 0e93cfc677..2cb06504ba 100644 --- a/specs/search/paths/synonyms/common/parameters.yml +++ b/specs/search/paths/synonyms/common/parameters.yml @@ -18,10 +18,14 @@ Type: name: type description: Only search for specific types of synonyms. schema: - type: string - enum: - - synonym - - onewaysynonym - - altcorrection1 - - altcorrection2 - - placeholder + $ref: '#/SynonymType' + +SynonymType: + type: string + description: Type of the synonym object. + enum: + - synonym + - onewaysynonym + - altcorrection1 + - altcorrection2 + - placeholder diff --git a/specs/search/paths/synonyms/common/schemas.yml b/specs/search/paths/synonyms/common/schemas.yml index 182e27a255..7bb05be90d 100644 --- a/specs/search/paths/synonyms/common/schemas.yml +++ b/specs/search/paths/synonyms/common/schemas.yml @@ -13,14 +13,7 @@ synonymHit: type: string description: Unique identifier of the synonym object to be created or updated. type: - type: string - description: Type of the synonym object. - enum: - - synonym - - onewaysynonym - - altcorrection1 - - altcorrection2 - - placeholder + $ref: './parameters.yml#/SynonymType' synonyms: type: array diff --git a/templates/java/JSON.mustache b/templates/java/JSON.mustache index 5d0d5bcee3..00b5bd0d14 100644 --- a/templates/java/JSON.mustache +++ b/templates/java/JSON.mustache @@ -1,31 +1,54 @@ package {{invokerPackage}}; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.internal.bind.util.ISO8601Utils; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import io.gsonfire.GsonFireBuilder; -import io.gsonfire.TypeSelector; - -import okio.ByteString; - import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Field; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.text.DateFormat; import java.text.ParseException; import java.text.ParsePosition; -{{#java8}} import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; -{{/java8}} +import java.util.Collections; import java.util.Date; -import java.util.Locale; +import java.util.EnumMap; import java.util.HashMap; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.FieldNamingStrategy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.annotations.SerializedName; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.internal.Excluder; +import com.google.gson.internal.LinkedTreeMap; +import com.google.gson.internal.ObjectConstructor; +import com.google.gson.internal.Primitives; +import com.google.gson.internal.bind.MapTypeAdapterFactory; +import com.google.gson.internal.bind.util.ISO8601Utils; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import io.gsonfire.GsonFireBuilder; +import okio.ByteString; public class JSON { private Gson gson; @@ -41,6 +64,7 @@ public class JSON { private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); {{/jsr310}} private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter(); + private RetainFieldMapFactory mapAdapter = new RetainFieldMapFactory(); public static GsonBuilder createGson() { GsonFireBuilder fireBuilder = new GsonFireBuilder() @@ -83,6 +107,7 @@ public class JSON { .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) {{/jsr310}} .registerTypeAdapter(byte[].class, byteArrayAdapter) + .registerTypeAdapterFactory(mapAdapter) .create(); } @@ -491,5 +516,401 @@ public class JSON { sqlDateTypeAdapter.setFormat(dateFormat); return this; } +} + +// https://stackoverflow.com/questions/21458468/gson-wont-properly-serialise-a-class-that-extends-hashmap +class RetainFieldMapFactory implements TypeAdapterFactory { + + FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; + ConstructorConstructor constructorConstructor = new ConstructorConstructor( + Collections.>emptyMap()); + MapTypeAdapterFactory defaultMapFactory = new MapTypeAdapterFactory( + constructorConstructor, + false); + ReflectiveFilterMapFieldFactory defaultObjectFactory = new ReflectiveFilterMapFieldFactory( + constructorConstructor, + fieldNamingPolicy, + Excluder.DEFAULT); + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + final TypeAdapter mapAdapter = defaultMapFactory.create(gson, type); + if (mapAdapter != null) { + return (TypeAdapter) new RetainFieldMapAdapter( + mapAdapter, + defaultObjectFactory.create(gson, type)); + } + return mapAdapter; + } + + class RetainFieldMapAdapter extends TypeAdapter> { + + TypeAdapter> mapAdapter; + ReflectiveTypeAdapterFactory.Adapter> objectAdapter; + + RetainFieldMapAdapter( + TypeAdapter mapAdapter, + ReflectiveTypeAdapterFactory.Adapter objectAdapter) { + this.mapAdapter = mapAdapter; + this.objectAdapter = objectAdapter; + } + + @Override + public void write(final JsonWriter out, Map value) + throws IOException { + if (value == null) { + out.nullValue(); + return; + } + // 1.write object + StringWriter sw = new StringWriter(); + objectAdapter.write(new JsonWriter(sw), value); + + // 2.convert object to a map + Map objectMap = mapAdapter.fromJson(sw.toString()); + + // 3.overwrite fields in object to a copy map + value = new LinkedHashMap(value); + value.putAll(objectMap); + + // 4.write the copy map + mapAdapter.write(out, value); + } + + @Override + public Map read(JsonReader in) throws IOException { + // 1.create map, all key-value retain in map + Map map = mapAdapter.read(in); + + // 2.create object from created map + Map object = objectAdapter.fromJsonTree( + mapAdapter.toJsonTree(map)); + + // 3.remove fields in object from map + for (String field : objectAdapter.boundFields.keySet()) { + map.remove(field); + } + // 4.put map to object + object.putAll(map); + return object; + } + } + + static class ReflectiveFilterMapFieldFactory + extends ReflectiveTypeAdapterFactory { + + public ReflectiveFilterMapFieldFactory( + ConstructorConstructor constructorConstructor, + FieldNamingStrategy fieldNamingPolicy, + Excluder excluder) { + super(constructorConstructor, fieldNamingPolicy, excluder); + } + + @Override + protected boolean shouldFindFieldInClass( + Class willFindClass, + Class originalRaw) { + Class[] endClasses = new Class[] { + Object.class, + HashMap.class, + LinkedHashMap.class, + LinkedTreeMap.class, + Hashtable.class, + TreeMap.class, + ConcurrentHashMap.class, + IdentityHashMap.class, + WeakHashMap.class, + EnumMap.class, + }; + for (Class c : endClasses) { + if (willFindClass == c) + return false; + } + + return super.shouldFindFieldInClass(willFindClass, originalRaw); + } + } + + /** + * below code copy from + * {@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory} (little + * modify, in source this class is final) Type adapter that reflects over the + * fields and methods + * of a class. + */ + static class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { + + private final ConstructorConstructor constructorConstructor; + private final FieldNamingStrategy fieldNamingPolicy; + private final Excluder excluder; + + public ReflectiveTypeAdapterFactory( + ConstructorConstructor constructorConstructor, + FieldNamingStrategy fieldNamingPolicy, + Excluder excluder) { + this.constructorConstructor = constructorConstructor; + this.fieldNamingPolicy = fieldNamingPolicy; + this.excluder = excluder; + } + + public boolean excludeField(Field f, boolean serialize) { + return (!excluder.excludeClass(f.getType(), serialize) && + !excluder.excludeField(f, serialize)); + } + + private String getFieldName(Field f) { + SerializedName serializedName = f.getAnnotation(SerializedName.class); + return serializedName == null + ? fieldNamingPolicy.translateName(f) + : serializedName.value(); + } + public Adapter create(Gson gson, final TypeToken type) { + Class raw = type.getRawType(); + + if (!Object.class.isAssignableFrom(raw)) { + return null; // it's a primitive! + } + + ObjectConstructor constructor = constructorConstructor.get(type); + return new Adapter(constructor, getBoundFields(gson, type, raw)); + } + + private ReflectiveTypeAdapterFactory.BoundField createBoundField( + final Gson context, + final Field field, + final String name, + final TypeToken fieldType, + boolean serialize, + boolean deserialize) { + final boolean isPrimitive = Primitives.isPrimitive( + fieldType.getRawType()); + + // special casing primitives here saves ~5% on Android... + return new ReflectiveTypeAdapterFactory.BoundField( + name, + serialize, + deserialize) { + final TypeAdapter typeAdapter = context.getAdapter(fieldType); + + @SuppressWarnings({ "unchecked", "rawtypes" }) // the type adapter and field type always agree + @Override + void write(JsonWriter writer, Object value) + throws IOException, IllegalAccessException { + Object fieldValue = field.get(value); + TypeAdapter t = new TypeAdapterRuntimeTypeWrapper( + context, + this.typeAdapter, + fieldType.getType()); + t.write(writer, fieldValue); + } + + @Override + void read(JsonReader reader, Object value) + throws IOException, IllegalAccessException { + Object fieldValue = typeAdapter.read(reader); + if (fieldValue != null || !isPrimitive) { + field.set(value, fieldValue); + } + } + }; + } + + private Map getBoundFields( + Gson context, + TypeToken type, + Class raw) { + Map result = new LinkedHashMap(); + if (raw.isInterface()) { + return result; + } + + Type declaredType = type.getType(); + Class originalRaw = type.getRawType(); + while (shouldFindFieldInClass(raw, originalRaw)) { + Field[] fields = raw.getDeclaredFields(); + for (Field field : fields) { + boolean serialize = excludeField(field, true); + boolean deserialize = excludeField(field, false); + if (!serialize && !deserialize) { + continue; + } + field.setAccessible(true); + Type fieldType = $Gson$Types.resolve( + type.getType(), + raw, + field.getGenericType()); + BoundField boundField = createBoundField( + context, + field, + getFieldName(field), + TypeToken.get(fieldType), + serialize, + deserialize); + BoundField previous = result.put(boundField.name, boundField); + if (previous != null) { + throw new IllegalArgumentException( + declaredType + + " declares multiple JSON fields named " + + previous.name); + } + } + type = TypeToken.get( + $Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass())); + raw = type.getRawType(); + } + return result; + } + + protected boolean shouldFindFieldInClass( + Class willFindClass, + Class originalRaw) { + return willFindClass != Object.class; + } + + abstract static class BoundField { + final String name; + final boolean serialized; + final boolean deserialized; + + protected BoundField( + String name, + boolean serialized, + boolean deserialized) { + this.name = name; + this.serialized = serialized; + this.deserialized = deserialized; + } + + abstract void write(JsonWriter writer, Object value) + throws IOException, IllegalAccessException; + + abstract void read(JsonReader reader, Object value) + throws IOException, IllegalAccessException; + } + + public static final class Adapter extends TypeAdapter { + private final ObjectConstructor constructor; + private final Map boundFields; + + private Adapter( + ObjectConstructor constructor, + Map boundFields) { + this.constructor = constructor; + this.boundFields = boundFields; + } + + @Override + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + T instance = constructor.construct(); + + try { + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + BoundField field = boundFields.get(name); + if (field == null || !field.deserialized) { + in.skipValue(); + } else { + field.read(in, instance); + } + } + } catch (IllegalStateException e) { + throw new JsonSyntaxException(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + in.endObject(); + return instance; + } + + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + + out.beginObject(); + try { + for (BoundField boundField : boundFields.values()) { + if (boundField.serialized) { + out.name(boundField.name); + boundField.write(out, value); + } + } + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + out.endObject(); + } + } + } + + static class TypeAdapterRuntimeTypeWrapper extends TypeAdapter { + + private final Gson context; + private final TypeAdapter delegate; + private final Type type; + + TypeAdapterRuntimeTypeWrapper( + Gson context, + TypeAdapter delegate, + Type type) { + this.context = context; + this.delegate = delegate; + this.type = type; + } + + @Override + public T read(JsonReader in) throws IOException { + return delegate.read(in); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void write(JsonWriter out, T value) throws IOException { + // Order of preference for choosing type adapters + // First preference: a type adapter registered for the runtime type + // Second preference: a type adapter registered for the declared type + // Third preference: reflective type adapter for the runtime type (if it is a + // sub class of the declared type) + // Fourth preference: reflective type adapter for the declared type + + TypeAdapter chosen = delegate; + Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value); + if (runtimeType != type) { + TypeAdapter runtimeTypeAdapter = context.getAdapter( + TypeToken.get(runtimeType)); + if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) { + // The user registered a type adapter for the runtime type, so we will use that + chosen = runtimeTypeAdapter; + } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) { + // The user registered a type adapter for Base class, so we prefer it over the + // reflective type adapter for the runtime type + chosen = delegate; + } else { + // Use the type adapter for runtime type + chosen = runtimeTypeAdapter; + } + } + chosen.write(out, value); + } + + /** Finds a compatible runtime type if it is more specific */ + private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) { + if (value != null && + (type == Object.class || + type instanceof TypeVariable || + type instanceof Class)) { + type = value.getClass(); + } + return type; + } + } } diff --git a/templates/java/StringUtil.mustache b/templates/java/StringUtil.mustache deleted file mode 100644 index 4957c3b1c0..0000000000 --- a/templates/java/StringUtil.mustache +++ /dev/null @@ -1,69 +0,0 @@ -package {{invokerPackage}}; - -import java.util.Collection; -import java.util.Iterator; - -public class StringUtil { - /** - * Check if the given array contains the given value (with case-insensitive comparison). - * - * @param array The array - * @param value The value to search - * @return true if the array contains the value - */ - public static boolean containsIgnoreCase(String[] array, String value) { - for (String str : array) { - if (value == null && str == null) { - return true; - } - if (value != null && value.equalsIgnoreCase(str)) { - return true; - } - } - return false; - } - - /** - * Join an array of strings with the given separator. - * - * Note: This might be replaced by utility method from commons-lang or guava someday - * if one of those libraries is added as dependency. - * - * - * @param array The array of strings - * @param separator The separator - * @return the resulting string - */ - public static String join(String[] array, String separator) { - int len = array.length; - if (len == 0) { - return ""; - } - - StringBuilder out = new StringBuilder(); - out.append(array[0]); - for (int i = 1; i < len; i++) { - out.append(separator).append(array[i]); - } - return out.toString(); - } - - /** - * Join a list of strings with the given separator. - * - * @param list The list of strings - * @param separator The separator - * @return the resulting string - */ - public static String join(Collection list, String separator) { - Iterator iterator = list.iterator(); - StringBuilder out = new StringBuilder(); - if (iterator.hasNext()) { - out.append(iterator.next()); - } - while (iterator.hasNext()) { - out.append(separator).append(iterator.next()); - } - return out.toString(); - } -} diff --git a/templates/java/libraries/okhttp-gson/pom.mustache b/templates/java/libraries/okhttp-gson/pom.mustache index 7f48155402..b594cb0ef6 100644 --- a/templates/java/libraries/okhttp-gson/pom.mustache +++ b/templates/java/libraries/okhttp-gson/pom.mustache @@ -43,7 +43,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.9.0 true 128m @@ -177,12 +177,6 @@ gson-fire ${gson-fire-version} - - jakarta.annotation - jakarta.annotation-api - ${jakarta-annotation-version} - provided - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} @@ -190,8 +184,7 @@ ${java.version} 1.8.5 4.9.1 - 2.8.6 - 1.3.5 + 2.8.9 UTF-8 From 28c26f45d885d6302ec02cf910212db7cdf44542 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Tue, 25 Jan 2022 16:09:46 +0100 Subject: [PATCH 2/3] generate java --- .../model/OneOfstringbuiltInOperation.java | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java index 8ac01fc739..c833c61636 100644 --- a/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java +++ b/clients/algoliasearch-client-java-2/algoliasearch-core/com/algolia/model/OneOfstringbuiltInOperation.java @@ -1,20 +1,3 @@ package com.algolia.model; -import com.google.gson.annotations.SerializedName; - -public class OneOfstringbuiltInOperation { - - @SerializedName("_operation") - private String _operation; - - @SerializedName("value") - private String value; - - public void set_operation(String op) { - _operation = op; - } - - public void setValue(String value) { - this.value = value; - } -} +public class OneOfstringbuiltInOperation {} From aab71d43b7e1c1c943e7afe028f8c35bc95b5bb6 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Tue, 25 Jan 2022 17:18:37 +0100 Subject: [PATCH 3/3] fix ci script thanks to @bodinsamuel --- scripts/ci/create-client-matrix.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/ci/create-client-matrix.sh b/scripts/ci/create-client-matrix.sh index 413bd2672d..0d7e292157 100755 --- a/scripts/ci/create-client-matrix.sh +++ b/scripts/ci/create-client-matrix.sh @@ -21,11 +21,11 @@ CLIENTS=$(cat openapitools.json | jq --arg lang $LANGUAGE -c '."generator-cli".g to_test='{"client": []}' for pair in $CLIENTS; do - name=$(echo $pair | jq '.name') - folder=$(echo $pair | jq '.folder') - spec_changed=$(git diff --shortstat origin/$BASE_BRANCH..HEAD -- specs/$name | wc -l) - client_changed=$(git diff --shortstat origin/$BASE_BRANCH..HEAD -- $folder | wc -l) - if [[ $BASE_CHANGED == "true" || $spec_changed > 0 || $client_changed > 0 ]]; then + name=$(echo $pair | jq -r '.name') + folder=$(echo $pair | jq -r '.folder') + spec_changed=$(git diff --shortstat origin/$BASE_BRANCH..HEAD -- specs/$name | wc -l | tr -d ' ') + client_changed=$(git diff --stat origin/$BASE_BRANCH..HEAD -- $folder | wc -l | tr -d ' ') + if [[ $BASE_CHANGED == "true" || $spec_changed != "0" || $client_changed != "0" ]]; then to_test=$(echo $to_test | jq --argjson pair $pair '.client |= .+ [$pair]') fi done