Printing Kafka KTable Data - java

I have this method which input's a JSON payload. I want to create a K-table out of this payload, read the data out of it and print it.
So far, I am to create the KTable, but when I iterate over it, the control skips over it.
Please can anyone help me/guide me where am I going wrong or what I am I missing?
Thanks.
public void twilioKTable(JsonNode payloadJson) throws JsonProcessingException {
String payload = payloadJson.toString();
final StreamsBuilder builder = new StreamsBuilder();
final KTable<String, String> kTable = builder.table("testktable");
kTable.toStream().map((key, value) -> new KeyValue<>(key, value))
.foreach(new ForeachAction<String, String>() {
public void apply(String key, String value) {
System.out.println("From MAP " + key + ": Value " +
value);
}
});
}

You could also use .peek() method in KStream to print every key with value

Related

Java guava Splitter failing when there are duplicate keys

How we can handle duplicate keys while using java guava Splitter function. Here is the sample code which is encountering the following issue. Is there a better way to handle this issue.
String fieldSplit = " ";
String valueSplit = "=";
String message = "ip=1.2.9.0 error=NA ip=1.2.9.0";
Map<String, String> parserMap = Splitter.on(fieldSplit).omitEmptyStrings().withKeyValueSeparator(valueSplit).split(message);
Exception in thread "kv-plugin-ac801a38-66f1-4ffe-86ca-f9eb6c823842-StreamThread-1" org.apache.kafka.streams.errors.StreamsException: Exception caught in process. taskId=0_0, processor=KSTREAM-SOURCE-0000000000, topic=kv-input, partition=0, offset=22, stacktrace=java.lang.IllegalArgumentException: Duplicate key [ip] found.
Im getting the above error. Can somebody suggest a better way to handle this. Since im new to java.
Depends on what you want to do with the duplicate keys.
Map<String, String> is a key value storage that can have only unique keys and only one value.
If you want to store all those values you would need something like Map<String, List<String> or Guava Multimap.
In this case you cannot do this with the Splitter as it cannot handle duplicate keys. You would need to write the logic by yourself.
String fieldSplit = " ";
String valueSplit = "=";
String message = "ip=1.2.9.0 error=NA ip=1.2.9.0";
Map<String, List<String>> parserMap = new HashMap<>();
for (String part : message.split(" ")) {
String[] subparts = part.split("=", 2);
if (!parserMap.contains(subparts[0])) {
parserMap.put(subparts[0], new ArrayList<>());
}
parserMap.get(subparts[0]).add(subparts[1]);
}
If you want to omit those duplicate entries you can still use the Map<String, String> with something like this.
Map<String, String> parserMap = new HashMap<>();
for (String part : message.split(" ")) {
String[] subparts = part.split("=", 2);
if (!parserMap.contains(subparts[0])) {
parserMap.put(subparts[0], subparts[1]);
}
}
Throwing on a duplicate key is a documented behavior of MapSplitter#split, so depending on what you want, you have to write your own "key-value" spliter consisting of two splitters. Please look at examples below, you can collect results to map with desired behavior (overwrite or discard) or even try out collecting to ListMultimap, but it makes result's values being stored in lists, even if there's only one value.
public class SO66139006 {
private static final Splitter PAIRS_SPLITTER = Splitter.on(' '); // .trimResults().omitEmptyStrings() if necessary
private static final Splitter KEY_VALUE_SPLITTER = Splitter.on('=').limit(2);
#Test
public void shouldOverwriteValuesOnDuplicateKey() {
//given
String message = "ip=42.42.42.0 error=NA ip=1.2.9.0";
//when
Map<String, String> result = parseOverwritingValues(PAIRS_SPLITTER, KEY_VALUE_SPLITTER, message);
//then
assertThat(result) // {ip=1.2.9.0, error=NA}
.containsExactly(entry("ip", "1.2.9.0"), entry("error", "NA"));
}
private Map<String, String> parseOverwritingValues(Splitter pairsSplitter, Splitter keyValueSplitter, String message) {
return Streams.stream(pairsSplitter.split(message))
.map(keyValueSplitter::splitToList)
.collect(toImmutableMap(
list -> list.get(0),
list -> list.get(1),
(oldValue, newValue) -> newValue
));
}
#Test
public void shouldDiscardValuesOnDuplicateKey() {
//given
String message = "ip=42.42.42.0 error=NA ip=1.2.9.0";
//when
Map<String, String> result = parseDiscardingValues(PAIRS_SPLITTER, KEY_VALUE_SPLITTER, message);
//then
assertThat(result) // {ip=42.42.42.0, error=NA}
.containsExactly(entry("ip", "42.42.42.0"), entry("error", "NA"));
}
private Map<String, String> parseDiscardingValues(Splitter pairsSplitter, Splitter keyValueSplitter, String message) {
return Streams.stream(pairsSplitter.split(message))
.map(keyValueSplitter::splitToList)
.collect(toImmutableMap(
list -> list.get(0),
list -> list.get(1),
(oldValue, newValue) -> oldValue
));
}
#Test
public void shouldAppendValuesOnDuplicateKey() {
//given
String message = "ip=42.42.42.0 error=NA ip=1.2.9.0";
//when
ListMultimap<String, String> result = parseMultipleValues(PAIRS_SPLITTER, KEY_VALUE_SPLITTER, message);
//then
assertThat(result.asMap()) // {ip=[42.42.42.0, 1.2.9.0], error=[NA]}
.containsExactly(entry("ip", ImmutableList.of("42.42.42.0", "1.2.9.0")), entry("error", ImmutableList.of("NA")));
}
private ListMultimap<String, String> parseMultipleValues(Splitter pairsSplitter, Splitter keyValueSplitter, String message) {
return Streams.stream(pairsSplitter.split(message))
.map(keyValueSplitter::splitToList)
.collect(toImmutableListMultimap(
list -> list.get(0),
list -> list.get(1)
));
}
#Test
public void shouldThrowByDefault() {
//given
String fieldSplit = " ";
String valueSplit = "=";
String message = "ip=1.2.9.0 error=NA ip=1.2.9.0";
//when
final Throwable throwable = catchThrowable(() -> Splitter.on(fieldSplit).omitEmptyStrings().withKeyValueSeparator(valueSplit).split(message));
//then
assertThat(throwable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Duplicate key [ip] found.");
}
}

Map dynamic nested Json object to hashmap and store keys and values into two string variable with comma separated

I need to map dynamimc json nested object into hashmap I could come up with solution but I couldn't get expected output.
Here is code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
String keys = map.keySet().stream().collect(Collectors.joining(", "));
String values = map.values().stream().map(obj -> String.valueOf(obj)).collect(Collectors.joining(", "));
System.out.println("Keys: " + keys);
System.out.println("Values: " + values);
Sample Json
{
"name": "Notification 2",
"message": "Facebook",
"tags":[
{
"city" : "Matara",
"village" : "Mirissa"
}
]
}
Actual output :
name, message, tags Notification 2, Facebook, [{city=Matara,
village=Mirissa}]
Expected output
name, message, tags/city, tag/village
Notification 2, Facebook, Matara, Mirissa
In above logic you are not processing sub elements, check below code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
Map<String, String> keyValueMap = new HashMap<>();
map.forEach((key, value) -> {
if (value instanceof List) {
((List)value).stream().forEach(obj -> { // processing sub elements
if (obj instanceof Map) {
((Map)obj).forEach((k,v) -> {
keyValueMap.put(key+"/"+k, v.toString());
});
}
});
} else { // direct value, no subelement
keyValueMap.put(key, value.toString());
}
});
The above logic will work for only elements which are inside List, so you need modify above logic little more generic based on your input json structure.
Below logic is to print the data which can be optimzed , i have written below logic so that it will be easy to understand
keyValueMap.forEach((k, v) -> {
System.out.print(k+ ",");
});
System.out.println();
keyValueMap.forEach((k, v) -> {
System.out.print(v+ ",");
});
it will give out put as below
name,tags/city,message,tags/village,
Notification 2,Matara,Facebook,Mirissa,
Thanks
Prasad

Apache Beam Flatten Iterable<String>

In the below code after groupbyKey, I am getting PCollection>>. How to flatten the Iterable in the value before sending to FileIO.
.apply(GroupByKey.<String, String>create())
.apply("Write file to output",FileIO.< String, KV<String,String>>writeDynamic()
.by(KV::getKey)
.withDestinationCoder(StringUtf8Coder.of())
.via(Contextful.fn(KV::getValue), TextIO.sink())
.to("Out")
.withNaming(key -> FileIO.Write.defaultNaming("file-" + key, ".txt")));
Thanks for the kind help.
You need to use a ParDo to flatten the Iterable portion of the PCollection as shown below:-
PCollection<KV<String, Doc>> urlDocPairs = ...;
PCollection<KV<String, Iterable<Doc>>> urlToDocs =
urlDocPairs.apply(GroupByKey.<String, Doc>create());
PCollection<R> results =
urlToDocs.apply(ParDo.of(new DoFn<KV<String, Iterable<Doc>>, R>() {
{#literal #}ProcessElement
public void processElement(ProcessContext c) {
String url = c.element().getKey();
for <String,Doc> docsWithThatUrl : c.element().getValue();
c.output(docsWithThatUrl)
}}));

Android: How to add existing JSONObject to existing key

I have a data structure like this:
source: {
property_1: String,
property_2: String,
property_3: {
property_31: String
}
}
I want to have a function like this:
private JSONObject mergeProperty(JSONObject source, String propertyName, JSONObject newData)
in which, source is data above, propertyName = "property_3", and
newData: {
property_32: String,
property_33: int
}
with result of calling mergeProperty(source, "property_3", newData) as:
output: {
property_1: String,
property_2: String,
property_3: {
property_31: String,
property_32: String,
property_33: int
}
}
Is there any simple method to achieve this without having to map the JSON object to HashMap first? I found no built-in JSONObject function which corelates to my problem.
If I got your intention right, this code must do the job. Please, note, that this will mutate original source, so you might need to pass a copy, if mutating original one is not what you want. Also, here I assume that propertyName is on the first level of your source JSON, and is JSON, too, else this will throw a JSONException.
JSONObject mergeTarget = source.getJSONObject(propertyName);
Iterator<String> keys = newData.keys();
while (keys.hasNext()) {
String key = keys.next();
mergeTarget.put(key, newData.get(key));
}
Try accumulate method of org.json.JSONObject.
Below code may be useful to you.
public class Test {
public static void main(String[] args){
System.out.println("test");
JSONObject source = new JSONObject("{\"property_1\":\"String\",\"property_2\":\"String\",\"property_3\":{\"property_31\":\"String\"}}");
JSONObject newData = new JSONObject("{\"property_32\":\"String\",\"property_33\":\"int\"}");
System.out.println("Before merge :"+source.toString());
mergeProperty(source, "property_3", newData);
System.out.println("After merge :"+source.toString());
}
private static void mergeProperty(JSONObject source, String property, JSONObject newData){
for (Object key : newData.keySet()){
String keyStr = (String)key;
Object keyvalue = newData.get(keyStr);
source.getJSONObject(property).accumulate(keyStr , keyvalue);
}
}
}

How to convert map to url query string?

Do you know of any utility class/library, that can convert Map into URL-friendly query string?
Example:
I have a map:
"param1"=12,
"param2"="cat"
I want to get:
param1=12&param2=cat
final output
relativeUrl+param1=12&param2=cat
The most robust one I saw off-the-shelf is the URLEncodedUtils class from Apache Http Compoments (HttpClient 4.0).
The method URLEncodedUtils.format() is what you need.
It doesn't use map so you can have duplicate parameter names, like,
a=1&a=2&b=3
Not that I recommend this kind of use of parameter names.
Here's something that I quickly wrote; I'm sure it can be improved upon.
import java.util.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class MapQuery {
static String urlEncodeUTF8(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
static String urlEncodeUTF8(Map<?,?> map) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<?,?> entry : map.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(String.format("%s=%s",
urlEncodeUTF8(entry.getKey().toString()),
urlEncodeUTF8(entry.getValue().toString())
));
}
return sb.toString();
}
public static void main(String[] args) {
Map<String,Object> map = new HashMap<String,Object>();
map.put("p1", 12);
map.put("p2", "cat");
map.put("p3", "a & b");
System.out.println(urlEncodeUTF8(map));
// prints "p3=a+%26+b&p2=cat&p1=12"
}
}
I found a smooth solution using java 8 and polygenelubricants' solution.
parameters.entrySet().stream()
.map(p -> urlEncodeUTF8(p.getKey()) + "=" + urlEncodeUTF8(p.getValue()))
.reduce((p1, p2) -> p1 + "&" + p2)
.orElse("");
In Spring Util, there is a better way..,
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("key", key);
params.add("storeId", storeId);
params.add("orderId", orderId);
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("http://spsenthil.com/order").queryParams(params).build();
ListenableFuture<ResponseEntity<String>> responseFuture = restTemplate.getForEntity(uriComponents.toUriString(), String.class);
Update June 2016
Felt compelled to add an answer having seen far too many SOF answers with dated or inadequate answers to very common problem - a good library and some solid example usage for both parse and format operations.
Use org.apache.httpcomponents.httpclient library. The library contains this org.apache.http.client.utils.URLEncodedUtils class utility.
For example, it is easy to download this dependency from Maven:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
For my purposes I only needed to parse (read from query string to name-value pairs) and format (read from name-value pairs to query string) query strings. However, there are equivalents for doing the same with a URI (see commented out line below).
// Required imports
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// code snippet
public static void parseAndFormatExample() throws UnsupportedEncodingException {
final String queryString = "nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk";
System.out.println(queryString);
// => nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk
final List<NameValuePair> params =
URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8);
// List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), "UTF-8");
for (final NameValuePair param : params) {
System.out.println(param.getName() + " : " + param.getValue());
// => nonce : 12345
// => redirectCallbackUrl : http://www.bbc.co.uk
}
final String newQueryStringEncoded =
URLEncodedUtils.format(params, StandardCharsets.UTF_8);
// decode when printing to screen
final String newQueryStringDecoded =
URLDecoder.decode(newQueryStringEncoded, StandardCharsets.UTF_8.toString());
System.out.println(newQueryStringDecoded);
// => nonce=12345&redirectCallbackUrl=http://www.bbc.co.uk
}
This library did exactly what I needed and was able to replace some hacked custom code.
If you actually want to build a complete URI, try URIBuilder from Apache Http Compoments (HttpClient 4).
This does not actually answer the question, but it answered the one I had when I found this question.
I wanted to build on #eclipse's answer using java 8 mapping and reducing.
protected String formatQueryParams(Map<String, String> params) {
return params.entrySet().stream()
.map(p -> p.getKey() + "=" + p.getValue())
.reduce((p1, p2) -> p1 + "&" + p2)
.map(s -> "?" + s)
.orElse("");
}
The extra map operation takes the reduced string and puts a ? in front only if the string exists.
Another 'one class'/no dependency way of doing it, handling single/multiple:
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class UrlQueryString {
private static final String DEFAULT_ENCODING = "UTF-8";
public static String buildQueryString(final LinkedHashMap<String, Object> map) {
try {
final Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
final StringBuilder sb = new StringBuilder(map.size() * 8);
while (it.hasNext()) {
final Map.Entry<String, Object> entry = it.next();
final String key = entry.getKey();
if (key != null) {
sb.append(URLEncoder.encode(key, DEFAULT_ENCODING));
sb.append('=');
final Object value = entry.getValue();
final String valueAsString = value != null ? URLEncoder.encode(value.toString(), DEFAULT_ENCODING) : "";
sb.append(valueAsString);
if (it.hasNext()) {
sb.append('&');
}
} else {
// Do what you want...for example:
assert false : String.format("Null key in query map: %s", map.entrySet());
}
}
return sb.toString();
} catch (final UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
public static String buildQueryStringMulti(final LinkedHashMap<String, List<Object>> map) {
try {
final StringBuilder sb = new StringBuilder(map.size() * 8);
for (final Iterator<Entry<String, List<Object>>> mapIterator = map.entrySet().iterator(); mapIterator.hasNext();) {
final Entry<String, List<Object>> entry = mapIterator.next();
final String key = entry.getKey();
if (key != null) {
final String keyEncoded = URLEncoder.encode(key, DEFAULT_ENCODING);
final List<Object> values = entry.getValue();
sb.append(keyEncoded);
sb.append('=');
if (values != null) {
for (final Iterator<Object> listIt = values.iterator(); listIt.hasNext();) {
final Object valueObject = listIt.next();
sb.append(valueObject != null ? URLEncoder.encode(valueObject.toString(), DEFAULT_ENCODING) : "");
if (listIt.hasNext()) {
sb.append('&');
sb.append(keyEncoded);
sb.append('=');
}
}
}
if (mapIterator.hasNext()) {
sb.append('&');
}
} else {
// Do what you want...for example:
assert false : String.format("Null key in query map: %s", map.entrySet());
}
}
return sb.toString();
} catch (final UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
public static void main(final String[] args) {
// Examples: could be turned into unit tests ...
{
final LinkedHashMap<String, Object> queryItems = new LinkedHashMap<String, Object>();
queryItems.put("brand", "C&A");
queryItems.put("count", null);
queryItems.put("misc", 42);
final String buildQueryString = buildQueryString(queryItems);
System.out.println(buildQueryString);
}
{
final LinkedHashMap<String, List<Object>> queryItems = new LinkedHashMap<String, List<Object>>();
queryItems.put("usernames", new ArrayList<Object>(Arrays.asList(new String[] { "bob", "john" })));
queryItems.put("nullValue", null);
queryItems.put("misc", new ArrayList<Object>(Arrays.asList(new Integer[] { 1, 2, 3 })));
final String buildQueryString = buildQueryStringMulti(queryItems);
System.out.println(buildQueryString);
}
}
}
You may use either simple (easier to write in most cases) or multiple when required. Note that both can be combined by adding an ampersand...
If you find any problems let me know in the comments.
This is the solution I implemented, using Java 8 and org.apache.http.client.URLEncodedUtils. It maps the entries of the map into a list of BasicNameValuePair and then uses Apache's URLEncodedUtils to turn that into a query string.
List<BasicNameValuePair> nameValuePairs = params.entrySet().stream()
.map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
URLEncodedUtils.format(nameValuePairs, Charset.forName("UTF-8"));
There's nothing built into Java to do this. But, hey, Java is a programming language, so. Let's program it!
map
.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"))
This gives you param1=12&param2=cat. Now we need to join the URL and this bit together. You'd think you can just do: URL + "?" + theAbove but if the URL already contains a question mark, you have to join it all together with "&" instead. One way to check is to see if there's a question mark in the URL someplace already.
Also, I don't quite know what is in your map. If it's raw stuff, you probably have to safeguard the call to e.getKey() and e.getValue() with URLEncoder.encode or similar.
Yet another way to go is that you take a wider view. Are you trying to append a map's content to a URL, or... Are you trying to make an HTTP (S) request from a Java process with the stuff in the map as (additional) HTTP params? In the latter case, you can look into an HTTP library like OkHttp which has some nice APIs to do this job, then you can forego any need to mess about with that URL in the first place.
Using EntrySet and Streams:
map
.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
You can use a Stream for this, but instead of appending query parameters myself I'd use a Uri.Builder. For example:
final Map<String, String> map = new HashMap<>();
map.put("param1", "cat");
map.put("param2", "12");
final Uri uri =
map.entrySet().stream().collect(
() -> Uri.parse("relativeUrl").buildUpon(),
(builder, e) -> builder.appendQueryParameter(e.getKey(), e.getValue()),
(b1, b2) -> { throw new UnsupportedOperationException(); }
).build();
//Or, if you consider it more readable...
final Uri.Builder builder = Uri.parse("relativeUrl").buildUpon();
map.entrySet().forEach(e -> builder.appendQueryParameter(e.getKey(), e.getValue())
final Uri uri = builder.build();
//...
assertEquals(Uri.parse("relativeUrl?param1=cat&param2=12"), uri);
Here's a simple kotlin solution:
fun Map<String, String>.toUrlParams(): String =
entries.joinToString("&") {
it.key.toUrlEncoded() + "=" + it.value.toUrlEncoded()
}
fun String.toUrlEncoded(): String = URLEncoder.encode(
this, StandardCharsets.UTF_8
)
To improve a little bit upon #eclipse's answer: In Javaland a request parameter map is usually represented as a Map<String, String[]>, a Map<String, List<String>> or possibly some kind of MultiValueMap<String, String> which is sort of the same thing. In any case: a parameter can usually have multiple values. A Java 8 solution would therefore be something along these lines:
public String getQueryString(HttpServletRequest request, String encoding) {
Map<String, String[]> parameters = request.getParameterMap();
return parameters.entrySet().stream()
.flatMap(entry -> encodeMultiParameter(entry.getKey(), entry.getValue(), encoding))
.reduce((param1, param2) -> param1 + "&" + param2)
.orElse("");
}
private Stream<String> encodeMultiParameter(String key, String[] values, String encoding) {
return Stream.of(values).map(value -> encodeSingleParameter(key, value, encoding));
}
private String encodeSingleParameter(String key, String value, String encoding) {
return urlEncode(key, encoding) + "=" + urlEncode(value, encoding);
}
private String urlEncode(String value, String encoding) {
try {
return URLEncoder.encode(value, encoding);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Cannot url encode " + value, e);
}
}
If you need just the query string (not the whole URL) and you are using Spring Framework, you can do this:
import org.springframework.web.util.UriComponentsBuilder;
...
final String queryString = UriComponentsBuilder.newInstance()
.queryParam("many", "7", "14", "21")
.queryParam("single", "XYZ")
.build()
.toUri()
.getQuery();
System.out.println(queryString);
the result is:
many=7&many=14&many=21&single=XYZ
I make these functions than also send just the property name when the value is null.
public static String urlEncode(Map<?, ?> map) {
return map.entrySet().stream().map(
entry -> entry.getValue() == null
? urlEncode(entry.getKey())
: urlEncode(entry.getKey()) + "=" + urlEncode(entry.getValue())
).collect(Collectors.joining("&"));
}
public static String urlEncode(Object obj) {
return URLEncoder.encode(obj.toString(), StandardCharsets.UTF_8);
}
For multivalue map you can do like below (using java 8 stream api's)
Url encoding has been taken cared in this.
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
String urlQueryString = params.entrySet()
.stream()
.flatMap(stringListEntry -> stringListEntry.getValue()
.stream()
.map(s -> UriUtils.encode(stringListEntry.getKey(), StandardCharsets.UTF_8.toString()) + "=" +
UriUtils.encode(s, StandardCharsets.UTF_8.toString())))
.collect(Collectors.joining("&"));
Personally, I'd go for a solution like this, it's incredibly similar to the solution provided by #rzwitserloot, only subtle differences.
This solution is small, simple & clean, it requires very little in terms of dependencies, all of which are a part of the Java Util package.
Map<String, String> map = new HashMap<>();
map.put("param1", "12");
map.put("param2", "cat");
String output = "someUrl?";
output += map.entrySet()
.stream()
.map(x -> x.getKey() + "=" + x.getValue() + "&")
.collect(Collectors.joining("&"));
System.out.println(output.substring(0, output.length() -1));
Kotlin
mapOf(
"param1" to 12,
"param2" to "cat"
).map { "${it.key}=${it.value}" }
.joinToString("&")
a very lightweight answer it works for me
public static String queryStr(Map<String, String> data) throws UnsupportedEncodingException {
StringBuilder query = new StringBuilder();
for (Entry<String, String> entry : data.entrySet()) {
if (query.length() > 0) {
query.append('&');
}
query.append(entry.getKey()).append('=');
query.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return query.toString();
}

Categories

Resources