diff --git a/src/main/java/com/smartystreets/api/ClientBuilder.java b/src/main/java/com/smartystreets/api/ClientBuilder.java index bb6460f..4378a17 100644 --- a/src/main/java/com/smartystreets/api/ClientBuilder.java +++ b/src/main/java/com/smartystreets/api/ClientBuilder.java @@ -20,6 +20,7 @@ public class ClientBuilder { private Map customHeaders; private final String INTERNATIONAL_STREET_API_URL = "https://international-street.api.smartystreets.com/verify"; private final String US_AUTOCOMPLETE_API_URL = "https://us-autocomplete.api.smartystreets.com/suggest"; + private final String US_AUTOCOMPLETE_API_PRO_URL = "https://us-autocomplete-pro.api.smartystreets.com/lookup"; private final String US_EXTRACT_API_URL = "https://us-extract.api.smartystreets.com/"; private final String US_STREET_API_URL = "https://us-street.api.smartystreets.com/street-address"; private final String US_ZIP_CODE_API_URL = "https://us-zipcode.api.smartystreets.com/lookup"; @@ -128,6 +129,11 @@ public com.smartystreets.api.us_autocomplete.Client buildUsAutocompleteApiClient return new com.smartystreets.api.us_autocomplete.Client(this.buildSender(), this.serializer); } + public com.smartystreets.api.us_autocomplete_pro.Client buildUsAutocompleteProApiClient() { + this.ensureURLPrefixNotNull(this.US_AUTOCOMPLETE_API_PRO_URL); + return new com.smartystreets.api.us_autocomplete_pro.Client(this.buildSender(), this.serializer); + } + public com.smartystreets.api.us_extract.Client buildUsExtractApiClient() { this.ensureURLPrefixNotNull(this.US_EXTRACT_API_URL); return new com.smartystreets.api.us_extract.Client(this.buildSender(), this.serializer); diff --git a/src/main/java/com/smartystreets/api/us_autocomplete/GeolocateType.java b/src/main/java/com/smartystreets/api/GeolocateType.java similarity index 90% rename from src/main/java/com/smartystreets/api/us_autocomplete/GeolocateType.java rename to src/main/java/com/smartystreets/api/GeolocateType.java index e6f9d89..39f9048 100644 --- a/src/main/java/com/smartystreets/api/us_autocomplete/GeolocateType.java +++ b/src/main/java/com/smartystreets/api/GeolocateType.java @@ -1,4 +1,4 @@ -package com.smartystreets.api.us_autocomplete; +package com.smartystreets.api; /** * This field corresponds to the geolocate and geolocate_precision fields in the US Autocomplete API. diff --git a/src/main/java/com/smartystreets/api/us_autocomplete/Lookup.java b/src/main/java/com/smartystreets/api/us_autocomplete/Lookup.java index ae29b73..4ad05b8 100644 --- a/src/main/java/com/smartystreets/api/us_autocomplete/Lookup.java +++ b/src/main/java/com/smartystreets/api/us_autocomplete/Lookup.java @@ -1,6 +1,7 @@ package com.smartystreets.api.us_autocomplete; import java.util.ArrayList; +import com.smartystreets.api.GeolocateType; /** * In addition to holding all of the input data for this lookup, this class also
diff --git a/src/main/java/com/smartystreets/api/us_autocomplete_pro/Client.java b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Client.java new file mode 100644 index 0000000..37bdc49 --- /dev/null +++ b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Client.java @@ -0,0 +1,79 @@ +package com.smartystreets.api.us_autocomplete_pro; + + +import com.smartystreets.api.*; +import com.smartystreets.api.exceptions.SmartyException; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * This client sends lookups to the SmartyStreets US Autocomplete API,
+ * and attaches the results to the appropriate Lookup objects. + */ +public class Client { + private final Sender sender; + private final Serializer serializer; + + public Client(Sender sender, Serializer serializer) { + this.sender = sender; + this.serializer = serializer; + } + + public Suggestion[] send(Lookup lookup) throws SmartyException, IOException { + if (lookup == null || lookup.getPrefix() == null || lookup.getPrefix().length() == 0) + throw new SmartyException("Send() must be passed a Lookup with the prefix field set."); + + Request request = this.buildRequest(lookup); + + Response response = this.sender.send(request); + + Result result = this.serializer.deserialize(response.getPayload(), Result.class); + Suggestion[] suggestions = result.getSuggestions(); + lookup.setResult(suggestions); + + return suggestions; + } + + private Request buildRequest(Lookup lookup) { + Request request = new Request(); + + request.putParameter("prefix", lookup.getPrefix()); + request.putParameter("suggestions", lookup.getMaxSuggestionsStringIfSet()); + request.putParameter("city_filter", this.buildFilterString(lookup.getCityFilter())); + request.putParameter("state_filter", this.buildFilterString(lookup.getStateFilter())); + request.putParameter("prefer", this.buildPreferString(lookup.getPrefer())); + request.putParameter("prefer_ratio", lookup.getPreferRatioStringIfSet()); + if (lookup.getGeolocateType() != GeolocateType.NONE) { + request.putParameter("geolocate", "true"); + request.putParameter("geolocate_precision", lookup.getGeolocateType().getName()); + } + else request.putParameter("geolocate", "false"); + + return request; + } + + private String buildPreferString(ArrayList list) { + return buildStringFromList(list, ";"); + } + + private String buildFilterString(ArrayList list) { + return buildStringFromList(list, ","); + } + + private String buildStringFromList(ArrayList list, String separator) { + if (list.isEmpty()) + return null; + + String filterList = ""; + + for (String item : list) { + filterList += (item + separator); + } + + if (filterList.endsWith(separator)) + filterList = filterList.substring(0, filterList.length()-1); + + return filterList; + } +} diff --git a/src/main/java/com/smartystreets/api/us_autocomplete_pro/Lookup.java b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Lookup.java new file mode 100644 index 0000000..fb1004d --- /dev/null +++ b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Lookup.java @@ -0,0 +1,186 @@ +package com.smartystreets.api.us_autocomplete_pro; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import com.smartystreets.api.GeolocateType; + +/** + * In addition to holding all of the input data for this lookup, this class also
+ * will contain the result of the lookup after it comes back from the API. + * @see "https://smartystreets.com/docs/cloud/us-autocomplete-api#http-request-input-fields" + */ +public class Lookup { + final double PREFER_RATIO_DEFAULT = 1/3.0; + final int MAX_SUGGESTIONS_DEFAULT = 10; + + //region [ Fields ] + + private Suggestion[] result; + private String search; + private int maxSuggestions; + private ArrayList cityFilter; + private ArrayList stateFilter; + private ArrayList zipcodeFilter; + private ArrayList preferCity; + private ArrayList preferState; + private ArrayList preferZipcode; + private double preferRatio; + private GeolocateType preferGeolocation; + + //endregion + + //region [ Constructors ] + + /** + * If you use this constructor, don't forget to set the prefix. It is required. + */ + public Lookup() { + this.maxSuggestions = this.MAX_SUGGESTIONS_DEFAULT; + this.preferGeolocation = GeolocateType.CITY; + this.cityFilter = new ArrayList<>(); + this.stateFilter = new ArrayList<>(); + this.zipcodeFilter = new ArrayList<>(); + this.preferCity = new ArrayList<>(); + this.preferState = new ArrayList<>(); + this.preferZipcode = new ArrayList<>(); + this.preferRatio = this.PREFER_RATIO_DEFAULT; + } + + /** + * @param search The beginning of an address + */ + public Lookup(String search) { + this(); + this.search = search; + } + + //endregion + + //region [ Getters ] + + public Suggestion[] getResult() { + return this.result; + } + + public Suggestion getResult(int index) { + return this.result[index]; + } + + public String getSearch() { + return this.search; + } + + public ArrayList getCityFilter() { + return this.cityFilter; + } + + public ArrayList getStateFilter() { + return this.stateFilter; + } + + public ArrayList getPreferCity() { + return this.preferCity; + } + + public ArrayList getPreferState() { return this.preferState; } + + public ArrayList getPreferZipcode() { return this.preferZipcode; } + + public double getPreferRatio() { + return this.preferRatio; + } + + String getPreferRatioStringIfSet() { + if (this.preferRatio == this.PREFER_RATIO_DEFAULT) + return null; + return Double.toString(this.preferRatio); + } + + public GeolocateType getGeolocateType() { + return preferGeolocation; + } + + public int getMaxSuggestions() { + return maxSuggestions; + } + + String getMaxSuggestionsStringIfSet() { + if (this.maxSuggestions == this.MAX_SUGGESTIONS_DEFAULT) + return null; + return Integer.toString(this.maxSuggestions); + } + + //endregion + + //region [ Setters ] + + public void setResult(Suggestion[] result) { + this.result = result; + } + + public void setSearch(String search) { + this.search = search; + } + + public void setCityFilter(ArrayList cityFilter) { + this.cityFilter = cityFilter; + } + + public void setStateFilter(ArrayList stateFilter) { + this.stateFilter = stateFilter; + } + + public void setZipcodeFilter(ArrayList zipcodeFilter) { this.zipcodeFilter = zipcodeFilter ;} + + public void setPreferCity(ArrayList cities) { + this.preferCity = cities; + } + + public void setPreferState(ArrayList states) { this.preferState = states; } + + public void setPreferZipcode(ArrayList zipcodes) { this.preferZipcode = zipcodes; } + + /*** + * Sets the percentage of suggestions that are to be from preferred cities/states. + * @param preferRatio A decimal value, range [0, 1]. Default is 0.333333333. + * @see "https://smartystreets.com/docs/cloud/us-autocomplete-api#preference" + */ + public void setPreferRatio(double preferRatio) { + this.preferRatio = preferRatio; + } + + public void setGeolocateType(GeolocateType geolocateType) { + this.preferGeolocation = geolocateType; + } + + /*** + * Sets the maximum number of suggestions to return. + * @param maxSuggestions A positive integer range [1, 10]. Default is 10. + * @throws IllegalArgumentException + */ + public void setMaxSuggestions(int maxSuggestions) throws IllegalArgumentException{ + if (maxSuggestions > 0 && maxSuggestions <= this.MAX_SUGGESTIONS_DEFAULT) { + this.maxSuggestions = maxSuggestions; + } else { + throw new IllegalArgumentException("Max suggestions must be a positive integer no larger than 10."); + } + } + + public void addCityFilter(String city) { + this.cityFilter.add(city); + } + + public void addStateFilter(String stateAbbreviation) { + this.stateFilter.add(stateAbbreviation); + } + + public void addPreferCity(String city) { + this.preferCity.add(city); + } + + public void addPreferState(String state) { this.preferState.add(state); } + + public void addPreferZipcode(String zipcode) { this.preferZipcode.add(zipcode); } + + //endregion +} diff --git a/src/main/java/com/smartystreets/api/us_autocomplete_pro/Result.java b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Result.java new file mode 100644 index 0000000..c0af420 --- /dev/null +++ b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Result.java @@ -0,0 +1,17 @@ +package com.smartystreets.api.us_autocomplete_pro; + + +import com.google.api.client.util.Key; + +public class Result { + @Key("suggestions") + private Suggestion[] suggestions; + + public Suggestion[] getSuggestions() { + return this.suggestions; + } + + public Suggestion getSuggestion(int index) { + return this.suggestions[index]; + } +} diff --git a/src/main/java/com/smartystreets/api/us_autocomplete_pro/Suggestion.java b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Suggestion.java new file mode 100644 index 0000000..70665f6 --- /dev/null +++ b/src/main/java/com/smartystreets/api/us_autocomplete_pro/Suggestion.java @@ -0,0 +1,52 @@ +package com.smartystreets.api.us_autocomplete_pro; + +import com.google.api.client.util.Key; + +/** + * @see "https://smartystreets.com/docs/cloud/us-autocomplete-api#http-response" + */ +public class Suggestion { + //region [ Fields ] + + @Key("street_line") + private String streetLine; + + @Key("secondary") + private String secondary; + + @Key("city") + private String city; + + @Key("state") + private String state; + + @Key("zipcode") + private String zipcode; + + @Key("entries") + private Integer entries; + + //region [ Fields ] + + //region [ Getters ] + + public String getStreetLine() { + return streetLine; + } + + public String getSecondary() { return secondary; } + + public String getCity() { + return city; + } + + public String getState() { + return state; + } + + public String getZipcode() { return zipcode; } + + public Integer getEntries() { return entries; } + + //endregion +} diff --git a/src/main/java/examples/UsAutocompleteProExample.java b/src/main/java/examples/UsAutocompleteProExample.java new file mode 100644 index 0000000..0dfc317 --- /dev/null +++ b/src/main/java/examples/UsAutocompleteProExample.java @@ -0,0 +1,55 @@ +package examples; + +import com.smartystreets.api.StaticCredentials; +import com.smartystreets.api.exceptions.SmartyException; +import com.smartystreets.api.us_autocomplete_pro.*; +import com.smartystreets.api.ClientBuilder; + +import java.io.IOException; + +public class UsAutocompleteProExample { + public static void main(String[] args) throws IOException, SmartyException { + // We recommend storing your secret keys in environment variables. + StaticCredentials credentials = new StaticCredentials(System.getenv("SMARTY_AUTH_ID"), System.getenv("SMARTY_AUTH_TOKEN")); + Client client = new ClientBuilder(credentials).buildUsAutocompleteProApiClient(); + Lookup lookup = new Lookup("1 King St Apt"); + + client.send(lookup); + + System.out.println("*** Result with no filter ***"); + System.out.println(); + for (Suggestion suggestion : lookup.getResult()) { + System.out.println(suggestion.getStreetLine()); + System.out.println(suggestion.getSecondary()); + System.out.println(suggestion.getCity()); + System.out.println(", "); + System.out.println(suggestion.getState()); + System.out.println(", "); + System.out.println(suggestion.getZipcode()); + } + + // Documentation for input fields can be found at: + // https://smartystreets.com/docs/cloud/us-autocomplete-api#http-request-input-fields + + lookup.addStateFilter("MA"); + lookup.addCityFilter("Dorchester"); + lookup.addCityFilter("Boston"); + lookup.addPreferCity("Dorchester"); + lookup.setMaxSuggestions(5); + lookup.setPreferRatio(0.33333); + + Suggestion[] suggestions = client.send(lookup); // The client will also return the suggestions directly + + System.out.println(); + System.out.println("*** Result with some filters ***"); + for (Suggestion suggestion : suggestions) { + System.out.println(suggestion.getStreetLine()); + System.out.println(suggestion.getSecondary()); + System.out.println(suggestion.getCity()); + System.out.println(", "); + System.out.println(suggestion.getState()); + System.out.println(", "); + System.out.println(suggestion.getZipcode()); + } + } +}