All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.java.com.zerobounce.ZeroBounceSDK Maven / Gradle / Ivy

package com.zerobounce;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * The ZeroBounce main class. All the requests are implemented here.
 */
public class ZeroBounceSDK {

    private static volatile ZeroBounceSDK instance;

    public static ZeroBounceSDK getInstance() {
        // The implementation below uses a double-check locking mechanism to boost performance while keeping the
        // singleton thread-safe.
        if (instance == null) {
            synchronized (ZeroBounceSDK.class) {
                if (instance == null) {
                    instance = new ZeroBounceSDK();
                }
                return instance;
            }
        }
        return instance;
    }

    final String apiBaseUrl = "https://api.zerobounce.net/v2";
    private final String bulkApiBaseUrl = "https://bulkapi.zerobounce.net/v2";
    private final String bulkApiScoringBaseUrl = "https://bulkapi.zerobounce.net/v2/scoring";
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);

    private String apiKey;
    private int timeoutInMillis;
    private final Gson gson;

    private ZeroBounceSDK() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
        gsonBuilder.registerTypeAdapter(ZBSendFileResponse.class, new ZBSendFileResponse.Deserializer());
        gsonBuilder.registerTypeAdapter(Date.class, new GsonDateDeserializer());
        gson = gsonBuilder.create();
    }

    /**
     * Initializes the SDK.
     *
     * [timeoutInMillis] is set to 0 (no timeout by default)
     *
     * @param apiKey the API key
     */
    public void initialize(String apiKey) {
        this.apiKey = apiKey;
        timeoutInMillis = 0;
    }

    /**
     * Initializes the SDK.
     *
     * @param apiKey the API key
     * @param timeoutInMillis the timeout in milliseconds to use for all requests (0 for no timeout)
     */
    public void initialize(String apiKey, int timeoutInMillis) {
        this.apiKey = apiKey;
        this.timeoutInMillis = timeoutInMillis;
    }

    /**
     * Validates the given [email].
     *
     * @param email           the email address you want to validate
     * @param ipAddress       the IP Address the email signed up from (Can be blank)
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void validate(
            @NotNull String email,
            @Nullable String ipAddress,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                apiBaseUrl + "/validate?api_key=" + apiKey +
                        "&email=" + email +
                        "&ip_address=" + (ipAddress != null ? ipAddress : ""),
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * Validates a batch of emails.
     *
     * @param emails          the email addresses you want to validate
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void validateBatch(
            @NotNull List emails,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        Map body = new HashMap<>();
        body.put("api_key", apiKey);
        body.put("email_batch", emails);

        sendRequest(
                apiBaseUrl + "/validatebatch",
                body,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * Tries to guess the format of the given [email].
     *
     * @param domain          the email domain for which to find the email format
     * @param firstName       the first name of the person whose email format is being searched; optional
     * @param middleName      the middle name of the person whose email format is being searched; optional
     * @param lastName        the last name of the person whose email format is being searched; optional
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void guessFormat(
            @NotNull String domain,
            @Nullable String firstName,
            @Nullable String middleName,
            @Nullable String lastName,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        String url = apiBaseUrl + "/guessformat?api_key=" + apiKey + "&domain=" + domain;
        if (firstName != null) {
            url += "&first_name=" + firstName;
        }
        if (middleName != null) {
            url += "&middle_name=" + middleName;
        }
        if (lastName != null) {
            url += "&last_name=" + lastName;
        }

        sendRequest(
                url,
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * Returns the API usage between the given dates.
     *
     * @param startDate       the start date of when you want to view API usage
     * @param endDate         the end date of when you want to view API usage
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void getApiUsage(
            @NotNull Date startDate,
            @NotNull Date endDate,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                apiBaseUrl + "/getapiusage?api_key=" + apiKey
                        + "&start_date=" + dateFormat.format(startDate)
                        + "&end_date=" + dateFormat.format(endDate),
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * This API will tell you how many credits you have left on your account. It's simple, fast and easy to use.
     *
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void getCredits(
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                apiBaseUrl + "/getcredits?api_key=" + apiKey,
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * The sendFile API allows user to send a file for bulk email validation.
     *
     * @param file                    the file to send
     * @param emailAddressColumnIndex the column index of the email address in the file. Index starts from 1.
     * @param options                 the send file options
     * @param successCallback         the success callback
     * @param errorCallback           the error callback
     */
    public void sendFile(
            @NotNull File file,
            int emailAddressColumnIndex,
            @Nullable SendFileOptions options,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        _sendFile(false, file, emailAddressColumnIndex, options, successCallback, errorCallback);
    }

    /**
     * The scoringSendFile API allows user to send a file for bulk email validation.
     *
     * @param file                    the file to send
     * @param emailAddressColumnIndex the column index of the email address in the file. Index starts from 1.
     * @param options                 the send file options
     * @param successCallback         the success callback
     * @param errorCallback           the error callback
     */
    public void scoringSendFile(
            @NotNull File file,
            int emailAddressColumnIndex,
            @Nullable ScoringSendFileOptions options,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        SendFileOptions newOptions = null;

        if (options != null) {
            newOptions = new SendFileOptions()
                    .setReturnUrl(options.returnUrl)
                    .setHasHeaderRow(options.hasHeaderRow)
                    .setRemoveDuplicate(options.removeDuplicate);
        }

        _sendFile(true,
                file,
                emailAddressColumnIndex,
                newOptions,
                successCallback,
                errorCallback
        );
    }

    /**
     * The sendFile API allows user to send a file for bulk email validation. This method implements the actual
     * request logic.
     *
     * @param scoring                 *true* if the AI scoring should be used, or *false* otherwise
     * @param file                    the file to send
     * @param emailAddressColumnIndex the column index of the email address in the file. Index starts from 1
     * @param options                 the send file options
     * @param successCallback         the success callback
     * @param errorCallback           the error callback
     */
    private void _sendFile(
            @NotNull Boolean scoring,
            @NotNull File file,
            int emailAddressColumnIndex,
            @Nullable SendFileOptions options,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback) {

        String urlPath = (scoring ? bulkApiScoringBaseUrl : bulkApiBaseUrl) + "/sendfile";
        System.out.println("ZeroBounceSDK::sendFile urlPath=" + urlPath);

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost uploadFile = new HttpPost(urlPath);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();

            builder.addPart("api_key", new StringBody(apiKey, ContentType.TEXT_PLAIN));
            builder.addPart(
                    "email_address_column",
                    new StringBody(String.valueOf(emailAddressColumnIndex), ContentType.TEXT_PLAIN)
            );

            if (options != null) {
                if (options.returnUrl != null) {
                    builder.addPart("return_url",
                            new StringBody(options.returnUrl, ContentType.TEXT_PLAIN)
                    );
                }
                if (options.firstNameColumn > 0) {
                    builder.addPart("first_name_column",
                            new StringBody(String.valueOf(options.firstNameColumn), ContentType.TEXT_PLAIN)
                    );
                }
                if (options.lastNameColumn > 0) {
                    builder.addPart("last_name_column",
                            new StringBody(String.valueOf(options.lastNameColumn), ContentType.TEXT_PLAIN)
                    );
                }
                if (options.genderColumn > 0) {
                    builder.addPart("gender_column",
                            new StringBody(String.valueOf(options.genderColumn), ContentType.TEXT_PLAIN)
                    );
                }
                if (options.ipAddressColumn > 0) {
                    builder.addPart(
                            "ip_address_column",
                            new StringBody(String.valueOf(options.ipAddressColumn), ContentType.TEXT_PLAIN)
                    );
                }
                if (options.hasHeaderRow != null) {
                    builder.addPart(
                            "has_header_row",
                            new StringBody(String.valueOf(options.hasHeaderRow), ContentType.TEXT_PLAIN)
                    );
                }
                if (options.removeDuplicate != null) {
                    builder.addPart(
                            "remove_duplicate",
                            new StringBody(String.valueOf(options.removeDuplicate), ContentType.TEXT_PLAIN)
                    );
                }
            }

            builder.addPart("file", new FileBody(file));

            HttpEntity multipart = builder.build();
            uploadFile.setEntity(multipart);

            CloseableHttpResponse response = httpClient.execute(uploadFile);
            HttpEntity responseEntity = response.getEntity();
            int status = response.getStatusLine().getStatusCode();

            System.out.println("ZeroBounceSDK::sendFile status: " + status);

            StringBuilder content = new StringBuilder();
            try (BufferedReader in = new BufferedReader(new InputStreamReader(responseEntity.getContent()))) {
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    content.append(inputLine);
                }
            }

            String rsp = content.toString();

            System.out.println("ZeroBounceSDK::sendFile rsp=" + rsp);

            if (status > 299) {
                ErrorResponse errorResponse = ErrorResponse.parseError(rsp);
                errorCallback.onError(errorResponse);
            } else {
                Type type = new TypeToken() {
                }.getType();
                ZBSendFileResponse sendFileResponse = gson.fromJson(rsp, type);

                successCallback.onSuccess(sendFileResponse);
            }

        } catch (Exception e) {
            e.printStackTrace();
            ErrorResponse errorResponse = ErrorResponse.parseError(e.getMessage());
            errorCallback.onError(errorResponse);
        }
    }

    /**
     * Returns the status of a file submitted for email validation.
     *
     * @param fileId          the returned file ID when calling sendFile API
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void fileStatus(
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _fileStatus(false, fileId, successCallback, errorCallback);
    }

    /**
     * Returns the status of a file submitted for email validation using the AI Scoring request.
     *
     * @param fileId          the returned file ID when calling scoringSendFile API
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void scoringFileStatus(
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _fileStatus(true, fileId, successCallback, errorCallback);
    }

    /**
     * Returns the status of a file submitted for email validation. This method implements the actual request logic.
     *
     * @param scoring         *true* if the AI scoring should be used, or *false* otherwise
     * @param fileId          the returned file ID when calling either the sendFile or scoringSendFile APIs
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    private void _fileStatus(
            @NotNull Boolean scoring,
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                (scoring ? bulkApiScoringBaseUrl : bulkApiBaseUrl) + "/filestatus?api_key=" + apiKey + "&file_id=" + fileId,
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * The getFile API allows users to get the validation results file for the file been submitted using sendFile API.
     *
     * @param fileId          the returned file ID when calling sendFile API
     * @param downloadPath    the path to which to download the file
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void getFile(
            @NotNull String fileId,
            @NotNull String downloadPath,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _getFile(false, fileId, downloadPath, successCallback, errorCallback);
    }

    /**
     * The scoringGetFile API allows users to get the validation results file for the file been submitted using
     * scoringSendFile API.
     *
     * @param fileId          the returned file ID when calling sendFile API
     * @param downloadPath    the path to which to download the file
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void scoringGetFile(
            @NotNull String fileId,
            @NotNull String downloadPath,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _getFile(true, fileId, downloadPath, successCallback, errorCallback);
    }

    /**
     * The getFile API allows users to get the validation results file for the file that has  been submitted.
     * This method implements the actual request logic.
     *
     * @param scoring         *true* if the AI scoring should be used, or *false* otherwise
     * @param fileId          the returned file ID when calling sendFile API
     * @param downloadPath    the path to which to download the file
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    private void _getFile(
            @NotNull Boolean scoring,
            @NotNull String fileId,
            @NotNull String downloadPath,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        try {
            File file = new File(downloadPath);
            if (file.isDirectory()) {
                ErrorResponse errorResponse = ErrorResponse.parseError("Invalid file path");
                errorCallback.onError(errorResponse);
                return;
            }
            file.getParentFile().mkdirs();
            try (CloseableHttpClient client = HttpClients.createDefault()) {
                HttpGet downloadFile = new HttpGet(
                        (scoring ? bulkApiScoringBaseUrl : bulkApiBaseUrl) + "/getfile?api_key=" + apiKey + "&file_id=" + fileId
                );
                CloseableHttpResponse response = client.execute(downloadFile);
                HttpEntity entity = response.getEntity();
                String contentType = response.getFirstHeader("Content-Type").getValue();

                // Check that the Content-Type is application/json or not. If it's not, then the response is the actual
                // file. Otherwise, the server has returned a JSON error.
                if (!ContentType.APPLICATION_JSON.getMimeType().equals(contentType)) {
                    if (entity != null) {
                        FileOutputStream outStream = new FileOutputStream(file);
                        entity.writeTo(outStream);
                    }
                    ZBGetFileResponse rsp = new ZBGetFileResponse();
                    rsp.setLocalFilePath(downloadPath);
                    successCallback.onSuccess(rsp);
                } else {
                    ErrorResponse errorResponse = ErrorResponse.parseError(EntityUtils.toString(entity));
                    errorCallback.onError(errorResponse);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            ErrorResponse errorResponse = ErrorResponse.parseError(e.getMessage());
            errorCallback.onError(errorResponse);
        }
    }

    /**
     * Delete a file.
     *
     * @param fileId          the returned file ID when calling sendFile API
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void deleteFile(
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _deleteFile(false, fileId, successCallback, errorCallback);
    }

    /**
     * Delete a file submitted using the scoring API.
     *
     * @param fileId          the returned file ID when calling sendFile API
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void scoringDeleteFile(
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        _deleteFile(true, fileId, successCallback, errorCallback);
    }

    /**
     * Delete a file. This method implements the actual request logic.
     *
     * @param scoring         *true* if the AI scoring should be used, or *false* otherwise
     * @param fileId          the returned file ID when calling sendFile API
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    private void _deleteFile(
            @NotNull Boolean scoring,
            @NotNull String fileId,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                (scoring ? bulkApiScoringBaseUrl : bulkApiBaseUrl) + "/deletefile?api_key=" + apiKey + "&file_id=" + fileId,
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * The request returns data regarding opens, clicks, forwards and unsubscribes that have taken place in the past
     * 30, 90, 180 or 365 days.
     *
     * @param email           the email address
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    public void getActivityData(
            @NotNull String email,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback
    ) {
        if (invalidApiKey(errorCallback)) return;

        sendRequest(
                apiBaseUrl + "/activity?api_key=" + apiKey + "&email=" + email,
                null,
                new TypeToken() {
                },
                successCallback,
                errorCallback
        );
    }

    /**
     * Checks if the [apiKey] is invalid or not and if it is, then it throws an error through the provided
     * [errorCallback].
     *
     * @param errorCallback the error callback
     * @return **true** if the [apiKey] is null or **false** otherwise
     */
    private boolean invalidApiKey(@NotNull OnErrorCallback errorCallback) {
        if (apiKey == null) {
            ErrorResponse errorResponse = ErrorResponse.parseError(
                    "ZeroBounce SDK is not initialized. Please call ZeroBounceSDK.initialize(apiKey) first"
            );
            errorCallback.onError(errorResponse);
            return true;
        }
        return false;
    }

    /**
     * An interface that provides a single method for a success callback.
     */
    public interface OnSuccessCallback {
        void onSuccess(T response);
    }

    /**
     * An interface that provides a single method for an error callback.
     */
    public interface OnErrorCallback {
        void onError(ErrorResponse errorResponse);
    }

    /**
     * The helper method that handles any type of request.
     *
     * @param urlPath         the url
     * @param successCallback the success callback
     * @param errorCallback   the error callback
     */
    private  void sendRequest(
            @NotNull String urlPath,
            @Nullable Map body,
            @NotNull TypeToken typeToken,
            @NotNull OnSuccessCallback successCallback,
            @NotNull OnErrorCallback errorCallback) {
        try {
            System.out.println("ZeroBounceSDK::sendRequest urlPath=" + urlPath);

            URL url = new URL(urlPath);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestProperty("Accept", "application/json");
//            con.setRequestProperty("Content-Type", "application/json");

            if (body == null) {
                con.setRequestMethod("GET");
            } else {
                con.setRequestMethod("POST");
                con.setDoOutput(true);

                // Attach the body to the request
                byte[] out = gson.toJson(body).getBytes(StandardCharsets.UTF_8);
                int length = out.length;

                con.setFixedLengthStreamingMode(length);
                con.connect();
                try (OutputStream os = con.getOutputStream()) {
                    os.write(out);
                }
            }

            con.setConnectTimeout(timeoutInMillis);

            int status = con.getResponseCode();
            System.out.println("ZeroBounceSDK::sendRequest status: " + status);
            Reader streamReader;
            if (status > 299) {
                streamReader = new InputStreamReader(con.getErrorStream());
            } else {
                streamReader = new InputStreamReader(con.getInputStream());
            }

            StringBuilder content = new StringBuilder();
            try (BufferedReader in = new BufferedReader(streamReader)) {
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    content.append(inputLine);
                }
            }

            con.disconnect();
            String rsp = content.toString();

            System.out.println("ZeroBounceSDK::sendRequest rsp=" + rsp);

            if (status > 299) {
                ErrorResponse errorResponse = ErrorResponse.parseError(rsp);
                errorCallback.onError(errorResponse);
            } else {
                T response = gson.fromJson(rsp, typeToken.getType());
                successCallback.onSuccess(response);
            }
        } catch (Exception e) {
            e.printStackTrace();
            ErrorResponse errorResponse = ErrorResponse.parseError(e.getMessage());
            errorCallback.onError(errorResponse);
        }

    }

    /**
     * A class that can be used to configure the [sendFile] request.
     */
    public static class SendFileOptions {

        @Nullable
        String returnUrl;

        int firstNameColumn;

        int lastNameColumn;

        int genderColumn;

        int ipAddressColumn;

        @Nullable
        Boolean hasHeaderRow;

        @Nullable
        Boolean removeDuplicate;

        public SendFileOptions setReturnUrl(@Nullable String returnUrl) {
            this.returnUrl = returnUrl;
            return this;
        }

        public SendFileOptions setFirstNameColumn(int firstNameColumn) {
            this.firstNameColumn = firstNameColumn;
            return this;
        }

        public SendFileOptions setLastNameColumn(int lastNameColumn) {
            this.lastNameColumn = lastNameColumn;
            return this;
        }

        public SendFileOptions setGenderColumn(int genderColumn) {
            this.genderColumn = genderColumn;
            return this;
        }

        public SendFileOptions setIpAddressColumn(int ipAddressColumn) {
            this.ipAddressColumn = ipAddressColumn;
            return this;
        }

        public SendFileOptions setHasHeaderRow(@Nullable Boolean hasHeaderRow) {
            this.hasHeaderRow = hasHeaderRow;
            return this;
        }

        public SendFileOptions setRemoveDuplicate(@Nullable Boolean removeDuplicate) {
            this.removeDuplicate = removeDuplicate;
            return this;
        }
    }

    /**
     * A class that can be used to configure the [scoringSendFile] request.
     */
    public static class ScoringSendFileOptions {

        @NotNull
        String returnUrl = "";

        @NotNull
        Boolean hasHeaderRow = false;

        @Nullable
        Boolean removeDuplicate = null;

        public ScoringSendFileOptions setReturnUrl(@NotNull String returnUrl) {
            this.returnUrl = returnUrl;
            return this;
        }

        public ScoringSendFileOptions setHasHeaderRow(@NotNull Boolean hasHeaderRow) {
            this.hasHeaderRow = hasHeaderRow;
            return this;
        }

        public ScoringSendFileOptions setRemoveDuplicate(@Nullable Boolean removeDuplicate) {
            this.removeDuplicate = removeDuplicate;
            return this;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy