{"id":37018927,"url":"https://github.com/corese4rch/cvurl","last_synced_at":"2026-01-14T02:01:26.166Z","repository":{"id":36061766,"uuid":"193906027","full_name":"corese4rch/cvurl","owner":"corese4rch","description":"cVurl is an open-source wrapper for the Java HTTP client. It is written in Java 11 and can be used with any JDK 11.0.2 or newer.","archived":false,"fork":false,"pushed_at":"2023-03-10T17:56:47.000Z","size":502,"stargazers_count":54,"open_issues_count":10,"forks_count":1,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-07-25T16:28:59.998Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corese4rch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://corevalue.com.ua/"}},"created_at":"2019-06-26T13:05:57.000Z","updated_at":"2024-03-31T14:22:41.000Z","dependencies_parsed_at":"2023-01-16T12:37:52.731Z","dependency_job_id":null,"html_url":"https://github.com/corese4rch/cvurl","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/corese4rch/cvurl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corese4rch%2Fcvurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corese4rch%2Fcvurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corese4rch%2Fcvurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corese4rch%2Fcvurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corese4rch","download_url":"https://codeload.github.com/corese4rch/cvurl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corese4rch%2Fcvurl/sbom","scorecard":{"id":304857,"data":{"date":"2025-08-11","repo":{"name":"github.com/corese4rch/cvurl","commit":"971e79bccb2914c94dfde3a976b54570d616730a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.8,"checks":[{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/corese4rch/cvurl/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/corese4rch/cvurl/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/corese4rch/cvurl/release.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T21:47:02.590Z","repository_id":36061766,"created_at":"2025-08-17T21:47:02.590Z","updated_at":"2025-08-17T21:47:02.590Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T02:01:25.292Z","updated_at":"2026-01-14T02:01:26.155Z","avatar_url":"https://github.com/corese4rch.png","language":"Java","funding_links":["https://corevalue.com.ua/"],"categories":["网络编程"],"sub_categories":["Spring Cloud框架"],"readme":"![Logo](https://i.ibb.co/L66Ywrn/c-Vurl-sticker-600x300.png)\n\n[![Coverage Status](https://coveralls.io/repos/github/corese4rch/cvurl/badge.svg?branch=master\u0026kill_cache=1)](https://coveralls.io/github/corese4rch/cvurl?branch=master)\n[![Build Status](https://travis-ci.com/corese4rch/cvurl.svg?branch=dev)](https://travis-ci.com/corese4rch/cvurl)\n[![GNU License](https://img.shields.io/badge/license-GNU%20GPL%20v3-green.svg)](https://github.com/corese4rch/cvurl/blob/master/LICENSE)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.corese4rch/cvurl-io/badge.svg?kill_cache=1)](https://search.maven.org/search?q=g:com.github.corese4rch%20AND%20a:cvurl-io)\n\n## cVurl is an open-source wrapper for the [Java HTTP client](https://openjdk.java.net/groups/net/httpclient/intro.html). \n\n## Requirements \n **cVurl** is written in Java 11 and can be used with any JDK 11.0.2 or newer\n (mainly because of this [issue](https://bugs.openjdk.java.net/browse/JDK-8211437)).\n \n## Dependencies\n **cVurl** is built purely with Java 11, and one of our goals was to bring as few dependencies to your project as possible. The only dependencies that will be added to your project are:\n \n ```xml\n        //(1)\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.fasterxml.jackson.core\u003c/groupId\u003e\n            \u003cartifactId\u003ejackson-databind\u003c/artifactId\u003e\n            \u003cversion\u003e${jackson.core.version}\u003c/version\u003e\n            \u003coptional\u003etrue\u003c/optional\u003e\n        \u003c/dependency\u003e\n        //(2)\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.slf4j\u003c/groupId\u003e\n            \u003cartifactId\u003eslf4j-api\u003c/artifactId\u003e\n            \u003cversion\u003e${slf4j-api.version}\u003c/version\u003e\n            \u003cscope\u003eprovided\u003c/scope\u003e\n        \u003c/dependency\u003e\n```\nIf you choose to use something different from [Jackson](https://github.com/FasterXML/jackson), you shouldn't be worried about the first dependency.\nOn the other hand, if you do use Jackson  - leave it as is. The library will create a default ObjectMapper for you under the hood.\nAnd there is a high chance you will use some logging library, so [Slf4j](https://github.com/qos-ch/slf4j) shouldn't be an unexpected resident in your build file. (For comprehensive examples, please, navigate to [Examples](#examples) section)\n \n## Concept\nThe idea behind this project is simple - to make life easier for developers.\nWe, as developers, have used numerous HTTP clients (such as RestTemplate, Feign, plain OkHttp3 / OkHttp4, Apache HttpClient, and others) in our work. With the transition to Java 11, we started working with the new Java HTTP client. While all of the above tools are good, each of them has something we are not willing to tolerate.\n\nLet's take a look at the following example:\n\n_What if we want to get some memes from the Internet?_\n\n **OkHttp4 Example**\n ```java\npublic void okHttp() {\n    OkHttpClient okHttpClient = new OkHttpClient();\n    //GET\n    try {\n        ResponseBody body = okHttpClient.newCall(new Request.Builder()\n        .url(\"https://api.imgflip.com/get_memes\")\n        .build())\n        .execute()\n        .body();\n\n        if (body != null) {\n            System.out.println(\"OkHttp GET: \" + body.string());\n        }\n    } catch (IOException e) {\n        e.printStackTrace();\n    }\n}\n```\n\n**Plain Java 11 Example**\n\n```java\npublic void javaHttp() {\n    HttpClient client = HttpClient.newHttpClient();\n\n    //GET\n    try {\n        HttpResponse\u003cString\u003e response = client.send(HttpRequest.newBuilder()\n            .uri(URI.create(\"https://api.imgflip.com/get_memes\"))\n            .build(), HttpResponse.BodyHandlers.ofString());\n\n        System.out.println(\"Java HttpClient GET: \" + response.body());\n    } catch (IOException | InterruptedException e) {\n        e.printStackTrace();\n    }\n}\n``` \n\nWe, at [Avenga](https://www.avenga.com/), don't like checked exceptions at all. Null checks are something we detest even more. Therefore, we came up with the following:\n\n```java\npublic void cVurl() {\n    CVurl cVurl = new CVurl();\n\n    //GET\n    Response\u003cString\u003e response = cVurl.get(\"https://api.imgflip.com/get_memes\")\n        .asString()\n        .orElseThrow(RuntimeException::new);\n\n    System.out.println(\"CVurl GET: \" + response.getBody());\n}\n```    \nLooks much better, right? ;)\n\n_What about something a little more complex, like a POST request?_\n\nTo simplify the examples below, we will use the following data structure:\n```java\n@Data //Lombok annotation\npublic class Result {\n    private boolean success;\n    private Data data;\n\n    @lombok.Data\n    private static class Data {\n        private String url;\n        @JsonAlias(\"page_url\")\n        private String pageUrl;\n    }\n}\n```\n\n**OkHttp4 Example**\n```java\npublic void okHttp() {\n    OkHttpClient okHttpClient = new OkHttpClient();\n        \n    //POST\n    HttpUrl url = HttpUrl.parse(\"https://api.imgflip.com/caption_image\").newBuilder()\n        .addQueryParameter(\"template_id\", \"112126428\")\n        .addQueryParameter(\"username\", \"test-user\")\n        .addQueryParameter(\"password\", \"123test321\")\n        .addQueryParameter(\"text0\", \"text0\")\n        .addQueryParameter(\"text1\", \"text1\")\n        .build();\n\n    try {\n        ResponseBody body = okHttpClient.newCall(new Request.Builder()\n        .url(url)\n        .post(RequestBody.create(new byte[]{})).build())\n        .execute()\n        .body();\n\n        if (body != null) {\n            Result result = new ObjectMapper().readValue(body.string(), Result.class);\n            System.out.println(\"OkHttp POST: \" + result);\n        }\n    } catch (IOException e) {\n        e.printStackTrace();\n    }\n}\n```\n\n**Plain Java 11 Example**\n```java\npublic void javaHttp() {\n    HttpClient client = HttpClient.newHttpClient();\n\n    //POST\n    URI uri = HttpUrl.parse(\"https://api.imgflip.com/caption_image\").newBuilder()\n        .addQueryParameter(\"template_id\", \"112126428\")\n        .addQueryParameter(\"username\", \"test-user\")\n        .addQueryParameter(\"password\", \"123test321\")\n        .addQueryParameter(\"text0\", \"text0\")\n        .addQueryParameter(\"text1\", \"text1\")\n        .build()\n        .uri();\n\n    try {\n        HttpResponse\u003cString\u003e response = client.send(HttpRequest.newBuilder()\n        .uri(uri)\n        .method(\"POST\", HttpRequest.BodyPublishers.noBody())\n        .build(),\n        HttpResponse.BodyHandlers.ofString());\n\n        Result result = new ObjectMapper().readValue(response.body(), Result.class);\n        System.out.println(\"Java HttpClient POST: \" + result);\n\n    } catch (IOException | InterruptedException e) {\n        e.printStackTrace();\n    }\n}\n```\n\nAnd again, we see the same \"troubles\" - checked exceptions, checks for null, verbosity...\n\n**cVurl Example**\n```java\npublic void cVurl() {\n    CVurl cVurl = new CVurl();\n\n    //POST\n    Result result = cVurl.post(\"https://api.imgflip.com/caption_image\")\n        .queryParams(Map.of(\n                \"template_id\", \"112126428\",\n        \"username\", \"test-user\",\n        \"password\", \"123test321\",\n        \"text0\", \"text0\",\n        \"text1\", \"text1\"\n        ))\n        .asObject(Result.class);\n\n    System.out.println(\"CVurl POST: \" + result);\n}\n```\nAnd one more example - thanks to the basic mapper (which is Jackson by default), you can send Java objects in a request body without any problems.\n```java\npublic Optional\u003cUserCreatedResponseDto\u003e createUser(UserDto userDto) {\n    return cVurl.post(HOST + USERS)\n        .body(userDto)\n        .asObject(UserCreatedResponseDto.class, HttpStatus.CREATED);\n}\n``` \n\nAs easy as pie.\n\nInterested? We encourage you to try cVurl!\n\n## Java 11 HTTP Client missing features\n\n#### Form data\nThere is no built-in support to send a POST request with x-www-form-urlencoded,\nand to implement it with plain Java 11 HTTP client, you have to add several lines of code to create a custom BodyPublisher implementation.\n```java\npublic static HttpRequest.BodyPublisher ofFormData(Map\u003cObject, Object\u003e data) {\n    var builder = new StringBuilder();\n    for (Map.Entry\u003cObject, Object\u003e entry : data.entrySet()) {\n        if (builder.length() \u003e 0) {\n            builder.append(\"\u0026\");\n        }\n        builder.append(URLEncoder.encode(entry.getKey().toString(), StandardCharsets.UTF_8));\n        builder.append(\"=\");\n        builder.append(URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8));\n    }\n    return HttpRequest.BodyPublishers.ofString(builder.toString());\n}\n```\nWell, we bet you will try not to write something like that because that's not all.\n```java\nvar client = HttpClient.newHttpClient();\n\nMap\u003cObject, Object\u003e data = new HashMap\u003c\u003e();\ndata.put(\"id\", 1);\ndata.put(\"name\", \"a name\");\ndata.put(\"ts\", System.currentTimeMillis());\n\nvar request = HttpRequest.newBuilder()\n        .POST(ofFormData(data))\n        .uri(URI.create(\"https://localhost:8443/formdata\"))\n        .header(\"Content-Type\", \"application/x-www-form-urlencoded\")\n        .build();\n\nreturn client.sendAsync(request, BodyHandlers.ofString())\n        .thenApply(HttpResponse::body)\n        .exceptionally(e -\u003e \"Error: \" + e.getMessage())\n        .thenAccept(System.out::println);\n```\nWe don't like such verbosity. That's why we do everything for you under the hood. You will only be using this simple and beautiful (fingers crossed) API.\n###### cVurl form data example\n```java\npublic User createUserFromFormUrlencoded(Map\u003cString, String\u003e userMap) {\n    return cVurl.post(\"https://...\")\n        .formData(userMap) // will automatically add application/x-www-form-urlencoded header\n        .asObject(User.class, HttpStatus.CREATED) // we assume that API returns JSON that represents the User class\n        .orElseThrow(() -\u003e new RuntimeException(\"Some comprehensive explanation of what went wrong\"));\n}\n```\n\n#### Compression\nThe Java 11 HTTP Client does not process compressed responses and does not send an Accept-Encoding request header to request compressed responses by default. If we know the server can send back compressed data, we can request it by adding the Accept-Encoding header. In this example, we only want a compressed response if it's in the gzip format.\n\n```java\nvar client = HttpClient.newHttpClient();\nvar request = HttpRequest.newBuilder()\n        .GET()\n        .header(\"Accept-Encoding\", \"gzip\")\n        .uri(URI.create(\"https://localhost:8443/indexWithoutPush\"))\n        .build();\n```\n\nThe server can ignore this header and send the response uncompressed, or it accepts it and sends back gzipped data. In our application, we have to handle both cases unless you are sure that a server always sends back compressed data. To check if the data is compressed, the application reads the Content-Encoding response header. If the value is gzip, the application uses the built-in GZIPInputStream to decompress the response body. Otherwise, the data is not compressed, and no special processing is required.\n```java\ntry {\n    HttpResponse\u003cInputStream\u003e response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());\n\n    String encoding = response.headers().firstValue(\"Content-Encoding\").orElse(\"\");\n    if (encoding.equals(\"gzip\")) {\n        System.out.println(\"gzip compressed\");\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        try (InputStream is = new GZIPInputStream(response.body()); var autoCloseOs = os) {\n            is.transferTo(autoCloseOs);\n        }\n        System.out.println(new String(os.toByteArray(), StandardCharsets.UTF_8));\n    } else {\n        System.out.println(\"not compressed\");\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        try (var is = response.body(); var autoCloseOs = os) {\n            is.transferTo(autoCloseOs);\n        }\n        System.out.println(new String(os.toByteArray(), StandardCharsets.UTF_8));\n    }\n} catch (IOException io) {\n    io.printStackTrace();\n}\n```\n\nWow, this is too much. That is why we have provided this API for you to achieve the same at a lower development cost.\n###### cVurl compression example\n\n```java\npublic String singleUserAsStringCompressed(String userId) {\n    Response\u003cString\u003e response = cVurl.get(\"https://...\" + userId)\n        .acceptCompressed() //we mark that we expect gzip response from server\n        .asString()\n        .orElseThrow(() -\u003e new RuntimeException(\"An error occurred while executing the request\"));\n\n    if (response.status() == HttpStatus.OK) {\n        return response.getBody();\n    } else {\n        return \"Not what you expect to receive\";\n    }\n}\n```\n\n#### Multipart\nIf the server endpoint expects binary data in the body, the application can send a POST request using the BodyPublishers.ofFile publisher. This publisher reads a file from the filesystem and sends the bytes in the body to the server. But in this case, we need to send the body in a specific format with the multipart/form-data value in the Content-Type header.  The request body is specially formatted as a series of parts, separated by boundaries. Unfortunately, the Java 11 HTTP client does not provide any convenient support for this type of request body, so we have to build it from scratch. The following method takes a map of key/value pairs and a boundary and then creates the multipart body.\n```java\npublic static HttpRequest.BodyPublisher ofMimeMultipartData(Map\u003cObject, Object\u003e data,\n        String boundary) throws IOException {\n    var byteArrays = new ArrayList\u003cbyte[]\u003e();\n    byte[] separator = (\"--\" + boundary + \"\\r\\nContent-Disposition: form-data; name=\").getBytes(StandardCharsets.UTF_8);\n    for (Map.Entry\u003cObject, Object\u003e entry : data.entrySet()) {\n        byteArrays.add(separator);\n\n        if (entry.getValue() instanceof Path) {\n            var path = (Path) entry.getValue();\n            String mimeType = Files.probeContentType(path);\n            byteArrays.add((\"\\\"\" + entry.getKey() + \"\\\"; filename=\\\"\" + path.getFileName()\n                + \"\\\"\\r\\nContent-Type: \" + mimeType + \"\\r\\n\\r\\n\").getBytes(StandardCharsets.UTF_8));\n            byteArrays.add(Files.readAllBytes(path));\n            byteArrays.add(\"\\r\\n\".getBytes(StandardCharsets.UTF_8));\n        } else {\n            byteArrays.add((\"\\\"\" + entry.getKey() + \"\\\"\\r\\n\\r\\n\" + entry.getValue() + \"\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        }\n    }\n    byteArrays.add((\"--\" + boundary + \"--\").getBytes(StandardCharsets.UTF_8));\n    return HttpRequest.BodyPublishers.ofByteArrays(byteArrays);\n}\n```\n\n```java\ntry {\n    Map\u003cObject, Object\u003e data = new LinkedHashMap\u003c\u003e();\n    data.put(\"file\", localFile);\n    String boundary = new BigInteger(256, new Random()).toString();\n\n    request = HttpRequest.newBuilder()\n        .header(\"Content-Type\", \"multipart/form-data;boundary=\" + boundary)\n        .POST(ofMimeMultipartData(data, boundary))\n        .uri(URI.create(\"https://...\"))\n        .build();\n\n    HttpResponse\u003cString\u003e vtResponse = client.send(request, HttpResponse.BodyHandlers.ofString());\n\n    try (JsonReader jsonReader = Json.createReader(new StringReader(vtResponse.body()))) {\n        JsonObject jobj = jsonReader.readObject();\n        String resource = jobj.getString(\"resource\");\n        URI uri = UrlBuilder.fromString(\"https://www.virustotal.com/vtapi/v2/file/report\")\n        .addParameter(\"apikey\", virusTotalApiKey).addParameter(\"resource\", resource)\n        .toUri();\n\n        HttpResponse\u003cString\u003e status = client.send(HttpRequest.newBuilder(uri).build(), HttpResponse.BodyHandlers.ofString());\n    }\n} catch (IOException io) {\n    io.printStackTrace();\n}\n```\n\nWe've tried our best to overcome these dozens of lines of code, and here's what we've created for you.\n###### cVurl multipart example \n```java\n@PostMapping(\"/photos\") // we are using Spring to represent the multipart example\npublic ResponseEntity uploadPhoto(@RequestParam MultipartFile photo, @RequestParam String title) throws IOException {\n    Response\u003cString\u003e response = cVurl.post(HOST + PHOTOS)\n        .body(MultipartBody.create()\n                .formPart(\"title\", Part.of(title))\n                .formPart(\"photo\", Part.of(photo.getName(), photo.getContentType(), photo.getBytes())))\n        .asString()\n        .orElseThrow(() -\u003e new RuntimeException(\"An error occurred while executing the request\"));\n\n    return ResponseEntity.status(response.status()).build();\n}\n```\n\n## How to get cVurl\nWell, as simple as everything else about cVurl.\n \n **Maven**\n ```xml\n\u003cdependecies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.github.corese4rch\u003c/groupId\u003e\n        \u003cartifactId\u003ecvurl-io\u003c/artifactId\u003e\n        \u003cversion\u003e1.5.1\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n **Gradle**\n```groovy\ncompile group: 'com.github.corese4rch', name: 'cvurl-io', version: '1.5.1'\n```\n   \n## Examples\nExamples can be found on our [Wiki page](https://github.com/corese4rch/cvurl/wiki).\n \n## Changelog\nPlease see the [changelog](https://github.com/corese4rch/cvurl/wiki/Changelog) page to see what's recently changed.\n   \n## License\n \u003e  Copyright 2019-2022 Avenga. Licensed under GNU GPLv3 \n  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorese4rch%2Fcvurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorese4rch%2Fcvurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorese4rch%2Fcvurl/lists"}