How to handle UNICODE URL? - java

If I want to pase the following URL's in Java:
... what handle should I have with the String.
So far I have been unable to handle that String's, all I've got are ???? chars.
Thanks.
Modified in 2012.09.09:
package pruebas;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Vector;
public class Prueba03
{
public static void main(String argumentos[])
{
Vector<String> listaURLs = new Vector<String>();
listaURLs.add("http://президент.рф/");
listaURLs.add("http://www.中国政府.政务.cn");
listaURLs.add("http://www.原來我不帥.cn/");
listaURLs.add("http://وزارة-الأتصالات.مصر/");
URL currentURL;
URLConnection currentConnection;
int currentSize;
for(int i=0; i<listaURLs.size(); i++)
{
try
{
System.out.println(URLDecoder.decode(listaURLs.get(i), URLEncoder.encode(listaURLs.get(i), "UTF-8")));
} // End of the try.
catch(UnsupportedEncodingException uee)
{
uee.printStackTrace();
} // End of the catch.
catch(Exception e)
{
e.printStackTrace();
} // End of the catch.
try
{
currentURL = new URL(listaURLs.get(i));
System.out.println("currentURL" + " = " + currentURL);
currentConnection = currentURL.openConnection();
System.out.println("currentConnection" + " = " + currentConnection);
currentSize = currentConnection.getContentLength();
System.out.println("currentSize" + " = " + currentSize);
} // End of the try.
catch(Exception e)
{
e.printStackTrace();
} // End of the catch.
} // End of the for.
} // End of the main method.
} // End of the Prueba02 class.

For domain name, you should convert unicode host name using Punycode.
Punycode is a way to convert unicode string to ascii string.
The following link shows a JAVA method to convert Unicode Domain Name to International Domain Name.
https://docs.oracle.com/javase/6/docs/api/java/net/IDN.html#toASCII(java.lang.String)
URL u = new URL(url);
String host = u.getHost();
String[] labels = host.split("\\.");
for (int i = 0; i < labels.length; i++) {
labels[i] = java.net.IDN.toUnicode(labels[i]);
}
host = StringUtils.join(labels, ".");
System.out.println(host);
Also, you can test some unicode URL using online punycode converter.
https://www.punycoder.com/
For example, "http://www.中国政府.政务.cn" is converted into "http://www.xn--fiqs8sirgfmh.xn--zfr164b.cn/".

Based on #hyunjong answer its not working to use toUnicode, use toASCII instead. And if you prefer kotlin, you can use this code
val a = "http://www.中国政府.政务.cn"
val u = URL(a);
val labels = u.host.split("\\.");
val result = labels.joinToString(separator = ".") { s ->
java.net.IDN.toASCII(s)
}
print(result) //www.xn--fiqs8sirgfmh.xn--zfr164b.cn

You can try the follow code:
import java.net.URLDecoder;
import java.net.URLEncoder;
public class Test7 {
public static void main(String[] args) throws Exception {
String str = "http://www.中国政府.政务.cn";
System.out.println(URLDecoder.decode(str, URLEncoder.encode(str,
"UTF-8")));
}
}

Not sure what do you mean by "parse" - what do you intend to do with these parts?
Arabic and Russian, as far as I know are supported by UTF-8.
Not sure what is your source of data (some sort of Stream perhaps?) but String has a CTOR that accepts the desired encoding.
You should be able to obtain a string NOT containing ??? when it comes to Arabic and Russian if you use this CTOR (with the "UTF-8" argument)

You may try use the following:
String pageUrl = "http://www.中国政府.政务.cn";
try
{
URL url = new URL(pageUrl);
System.out.println(url.toURI().toASCIIString());
}
catch (MalformedURLException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (URISyntaxException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
The result is as expected:
http://www.%E4%B8%AD%E5%9B%BD%E6%94%BF%E5%BA%9C.%E6%94%BF%E5%8A%A1.cn
But converting to URI has its own disadvantage, you should replace manually the special characters like '|', '"', '#' to its URL encoding.

Related

How to iterate over Java 8 String Stream and append line to String?

I have a method using the code below based on other resources how to iterate a file using a Java 8 stream:
String result = "";
try (Stream<String> stream = Files.lines(Paths.get("/home/user/file.txt"))) {
stream.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
However, I want to save the lines to += a string, instead of console.
I have tried these 2 below but neither pass IDE validation:
stream.forEach(thisString -> result += thisString);
stream.forEach(result += this);
stream.forEach(result::this);
What is the proper way to append each result from the foreach loop to a String object?
If you just want to read the whole file as String, there is no need to use a Stream. If you are using Java 11, you can just use Files.readString():
try {
String result = Files.readString(Paths.get("/home/user/file.txt"));
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
If you need a Java 8 solution, see Holger's comment.
Hadi J has given you the answer in his comment
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FileJoin {
public static void main(String[] args) {
String result = "";
try (Stream<String> stream = Files.lines(Paths.get("/home/user/file.txt"))) {
result = stream.collect(Collectors.joining());
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(result);
}
}

Convert Java HmacMD5 function to VB6

I'm working on a windows app, and need to use some auth function from some previous java code. I have access to the Java source but still can't seem to get it right. Probably because of my limited knowledge of cryptography.
The Java functions I need to convert are :
public String getHMACHash(String SharedSecretKey, String TextToHash) {
return base64EncodedStringFromBytes(hmacMD5(SharedSecretKey, TextToHash));
}
private String base64EncodedStringFromBytes(byte[] bArr) {
return Base64.encodeToString(bArr, 2);
}
public byte[] hmacMD5(String SharedSecretKey, String TextToHash) {
byte[] bArr = null;
try {
Mac instance = Mac.getInstance("HmacMD5");
instance.init(new SecretKeySpec(SharedSecretKey.getBytes(), "HmacMD5"));
bArr = instance.doFinal(TextToHash.getBytes());
} catch (NoSuchAlgorithmException e) {
Log.m8401e(TAG, e.getLocalizedMessage());
} catch (InvalidKeyException e2) {
Log.m8401e(TAG, e2.getLocalizedMessage());
}
return bArr;
}
so when inputting the values :
SharedSecretKey = "497n9x98jK06gf7S3T7wJ2k455Qm192Q"
TextToHash = "1502322764327/customerservice.svc/buybackcartPOST8e802a045c1e60e"
the Hash generated is :
pOZNkg077OdvhyeMMPIX2w==
Try as I might I can't get near to the hash key using the same values in VB6. I have tried a few different methods to create the hash :
Private Function hash_HMACMD5(ByVal sTextToHash As String, ByVal
sSharedSecretKey As String)
Dim asc As Object, enc As Object
Dim TextToHash() As Byte
Dim SharedSecretKey() As Byte
Set asc = CreateObject("System.Text.UTF8Encoding")
Set enc = CreateObject("System.Security.Cryptography.HMACMD5")
TextToHash = asc.Getbytes_4(sTextToHash)
SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)
enc.Key = SharedSecretKey
Dim bytes() As Byte
bytes = enc.ComputeHash_2((TextToHash))
hash_HMACMD5 = Base64Encode(bytes)
Set asc = Nothing
Set enc = Nothing
End Function
So, I was hoping someone out there might be able to point me in the right direction ?
Thanks In advance for any help.
Potman100
I've traced all the code through, and I can't see any thing that would indicate something different is going on. As mentioned below, there is a import line
import android.util.Base64;
The call to create the hash is :
String hMACHash = new MASecurity().getHMACHash(str, str2);
MASecurity Class is :
import android.util.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class MASecurity {
private static final String TAG = "MASecurity";
public String getHMACHash(String str, String str2) {
return base64EncodedStringFromBytes(hmacMD5(str, str2));
}
private String base64EncodedStringFromBytes(byte[] bArr) {
return Base64.encodeToString(bArr, 2);
}
public byte[] hmacMD5(String str, String str2) {
byte[] bArr = null;
try {
Mac instance = Mac.getInstance("HmacMD5");
instance.init(new SecretKeySpec(str.getBytes(), "HmacMD5"));
bArr = instance.doFinal(str2.getBytes());
} catch (NoSuchAlgorithmException e) {
MALog.m8401e(TAG, e.getLocalizedMessage());
} catch (InvalidKeyException e2) {
MALog.m8401e(TAG, e2.getLocalizedMessage());
}
return bArr;
}
The input values are correct, as they are logged whilst the app is running.
Hope this helps ??
Thanks Alex K., seems the Java code was adding more data to one of the params which the debugging I did missed, one I added the extra data it creates a valid hash.

Decode multiple times encoded String

I have written Java code to decode a string encoded with "UTF-8". That String was encoded three times. I am using this code in the ETL. so, I can use an ETL step three times in a row, but it will be a little inefficient. I researched over the internet but didn't find anything promising. Is there any way in Java to decode the String encoded multiple times?
Here's my input string "uri":
file:///C:/Users/nikhil.karkare/dev/pentaho/data/ba-repo-content-original/public/Development+Activity/Defects+Unresolved+%252528by+Non-Developer%252529.xanalyzer
Here's my code which is decoding this string:
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.io.*;
String decodedValue;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
// First, get a row from the default input hop
//
Object[] r = getRow();
// If the row object is null, we are done processing.
//
if (r == null) {
setOutputDone();
return false;
}
// It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
// enough to handle any new fields you are creating in this step.
//
Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());
String newFileName = get(Fields.In, "uri").getString(r);
try{
decodedValue = URLDecoder.decode(newFileName, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new AssertionError("UTF-8 is unknown");
}
// Set the value in the output field
//
get(Fields.Out, "decodedValue").setValue(outputRow, decodedValue);
// putRow will send the row on to the default output hop.
//
putRow(data.outputRowMeta, outputRow);
return true;}
Output of this code is following:
file:///C:/Users/nikhil.karkare/dev/pentaho/data/ba-repo-content-original/public/Development Activity/Defects Unresolved %2528by Non-Developer%2529.xanalyzer
When I run this code in the ETL three times, I get the output I want, which is this:
file:///C:/Users/nikhil.karkare/dev/pentaho/data/ba-repo-content-original/public/Development Activity/Defects Unresolved (by Non-Developer).xanalyzer
URL encoding replaces %, ( and ) with resp. %25.%28 and %29.
String s = "file:///C:/Users/nikhil.karkare/dev/pentaho/data/"
+ "ba-repo-content-original/public/Development+Activity/"
+ "Defects+Unresolved+%252528by+Non-Developer%252529.xanalyzer";
// %253528 ... %252529
s = URLDecoder.decode(s, "UTF-8");
// %2528 ... %2529
s = URLDecoder.decode(s, "UTF-8");
// %28 .. %29
s = URLDecoder.decode(s, "UTF-8");
// ( ... )
Just a for loop did the job:
String newFileName = get(Fields.In, "uri").getString(r);
decodedValue = newFileName;
for (int i=0; i<=3; i++){
try{
decodedValue = URLDecoder.decode(decodedValue, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new AssertionError("UTF-8 is unknown");
}
}

Java String conversion to JSON can not be done

I have JSON which I get from server:
"[{\"id\":\"1\",\"name\":\"Milos\",\"city\":\"Smederevo\",\"email\":\"milos\",\"password\":\"\"},
{\"id\":\"3\",\"name\":\"Boban\",\"city\":\"Beograd\",\"email\":\"bole\",\"password\":\"\"},
{\"id\":\"4\",\"name\":\"Pele\",\"city\":\"Brazil\",\"email\":\"pele#pele.com\",\"password\":\"\"},
{\"id\":\"5\",\"name\":\"admin\",\"city\":\"Smederevo\",\"email\":\"admin\",\"password\":\"\"}]"
I am using that json and sending to my thread (android thread):
try {
// Method from which I am getting Json described above
String s = dm.getAllUsers();
/*JSONParser jp = new JSONParser();
JsonElement jelement = new JsonParser().parse(s);
JsonArray array1 = jelement.getAsJsonArray();*/
JSONArray array = new JSONArray(s);
for (int i = 0; i < array.length(); i++) {
JSONObject menuObject = array.getJSONObject(i);
// doing something with the object
}
} catch (JSONException e) {
e.printStackTrace();
}
I can not process that Json at all.
I am getting the error "java.lang.String cannot be converted to JSONArray".
A know that problem is caused by "\", and I just do not know how to get rid of "\".
I tried:
1) s.replace("\\", "");
2) s.replace("\"", "'");
3) s.replaceAll("\\", "");
4) s.replaceAll("\"", "'");
In order to erase "\" but replace do not react at all.
I also tried to solve problem with "google-gson-2.2.2" library (code under the comment above, under the method).
Any advice, please?
Try this solution.
s.replaceAll("\\\\", "");
This will definitely work.
Problem has been solved with:
1) s = s.trim();
2) s = s.substring(1, s.length()-1);
3) s = s.replace("\\", "");
My json has been retrieved with "double quotes" on the beginning and on the end. I do not know how string variable can not figure out that "double quotes" is for "beginning" and for "ending" of string.
Thank you everybody for helping.
It is working for me...
In your json the value of "Your Json" is inclused inside "" so it's considered a string not an array..
So the solution is one of two things:
If you can modify the server response, remove the "" from arround the json array. or parse it first as string and then create a json array from that string like..
String notes = jobj.getString("GetNotesResult");
jarray = new JSONArray(notes);
I have no idea why its not working for you. Dot net web services do respond with \ but Java capable of parsing it. I did as below and it worked.
I've coded like this.
JSONArray users = null;
String jsStr = "[{\"id\":\"1\",\"name\":\"Milos\",\"city\":\"Smederevo\",\"email\":\"milos\",\"password\":\"\"},{\"id\":\"3\",\"name\":\"Boban\",\"city\":\"Beograd\",\"email\":\"bole\",\"password\":\"\"},{\"id\":\"4\",\"name\":\"Pele\",\"city\":\"Brazil\",\"email\":\"pele#pele.com\",\"password\":\"\"}, {\"id\":\"5\",\"name\":\"admin\",\"city\":\"Smederevo\",\"email\":\"admin\",\"password\":\"\"}]";
try {
users = new JSONArray(jsStr);
} catch (JSONException e) {
e.printStackTrace();
}
Log.v("JSONStr", String.valueOf(users.length()));
for(int i = 0; i<users.length(); i++){
try {
Log.v("Name", users.getJSONObject(i).getString("name"));
} catch (JSONException e) {
e.printStackTrace();
}
}
See the LogCat
03-18 16:34:46.459: V/JSONStr(307): 4
03-18 16:34:46.479: V/Name(307): Milos
03-18 16:34:46.479: V/Name(307): Boban
03-18 16:34:46.479: V/Name(307): Pele
03-18 16:34:46.479: V/Name(307): admin
Your json will be valid only if you remove the back slashes () in between. You could use something like:
strJson = strJson.replaceAll("\\\\", ""); OR strJson = strJson.replace("\\", ""); to remove the slashes () in between your json String. Please note that replaceAll() method treats the first argument as a regex, so you must double escape the backslash but, the replace() method treats it as a literal string, so you only have to escape it once. Please have a look at the below example for better understanding: I have kept your json text in a file named json.txt in my hard-drive for demonstration. The contents in the file looks like this:
[{\"id\":\"1\",\"name\":\"Milos\",\"city\":\"Smederevo\",\"email\":\"milos\",\"password\":\"\"},
{\"id\":\"3\",\"name\":\"Boban\",\"city\":\"Beograd\",\"email\":\"bole\",\"password\":\"\"},
{\"id\":\"4\",\"name\":\"Pele\",\"city\":\"Brazil\",\"email\":\"pele#pele.com\",\"password\":\"\"},
{\"id\":\"5\",\"name\":\"admin\",\"city\":\"Smederevo\",\"email\":\"admin\",\"password\":\"\"}]
Now the code for getting the json array:
package com.stackoverflow.com;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class JsonTest {
public static void main(String[] args) {
try {
FileReader fileReader = new FileReader("C:/Users/sarath_sivan/Desktop/json.txt");
BufferedReader br = new BufferedReader(fileReader);
StringBuilder strJsonBuilder = new StringBuilder();
String strLine;
while((strLine = br.readLine()) != null) {
strJsonBuilder.append(strLine);
}
String strJson = strJsonBuilder.toString();
strJson = strJson.replaceAll("\\\\", ""); /*OR you can use strJson = strJson.replace("\\", "");*/
JSONArray jsonArray = new JSONArray(strJson);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject menuObject = jsonArray.getJSONObject(i);
System.out.println("id: " + menuObject.getInt("id"));
System.out.println("name: " + menuObject.getString("name"));
System.out.println("city: " + menuObject.getString("city"));
System.out.println("email: " + menuObject.getString("email"));
System.out.println("password: " + menuObject.getString("password"));
System.out.println();
// do something with your JSON
}
fileReader.close();
} catch (JSONException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
s = s.replace("\\", "");
System.out.println(s);
You need to assign your modified String back to s. This gives a proper parsable JSON.
I don't really like the various String.replaceAll(rexex, "") solutions. What if some of the strings in your JSON contain a \ as part of the information rather than the formatting? I see a 'password' field in your JSON. I don't know whether this is going to be clear text or a hash, but in the case of the former, your program might break if a user uses a backslash in their password.
What you want to do here is unescape a string. This is a problem that as far as I can tell, can't be solved with a simple regex, but it is a problem that has been solved thousands of times before. No need to reinvent the wheel.
How to unescape a string literal in java

Determining the path to Outlook.exe from java?

I want to invoke outlook from the command line (for various reasons) and wanted to know how I go about discovering the Path to the Outlook.exe file.
I'm pretty sure it's stored in the registry, but was wondering how to go about reading that from Java.
thanks
I found a Microsoft page that describes the procedure, just not in Java.
So I guess the question becomes how do I access the registry from java.
I found this site that might be able to help you. It's a Java Registry wrapper, seems to have a lot of features but no idea how robust the implementation is.
Using Otis' answer the following code does it nicely.
static String getOutlookPath() {
// Message message = new Message();
final String classID;
final String outlookPath;
{ // Fetch the Outlook Class ID
int[] ret = RegUtil.RegOpenKey(RegUtil.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\Outlook.Application\\CLSID", RegUtil.KEY_QUERY_VALUE);
int handle = ret[RegUtil.NATIVE_HANDLE];
byte[] outlookClassID = RegUtil.RegQueryValueEx(handle, "");
classID = new String(outlookClassID).trim(); // zero terminated bytes
RegUtil.RegCloseKey(handle);
}
{ // Using the class ID from above pull up the path
int[] ret = RegUtil.RegOpenKey(RegUtil.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\CLSID\\" + classID + "\\LocalServer32", RegUtil.KEY_QUERY_VALUE);
int handle = ret[RegUtil.NATIVE_HANDLE];
byte[] pathBytes = RegUtil.RegQueryValueEx(handle, "");
outlookPath = new String(pathBytes).trim(); // zero terminated bytes
RegUtil.RegCloseKey(handle);
}
return outlookPath;
}
Below is a solution modified slightly from a similar problem: https://stackoverflow.com/a/6194710/854664
Notice I'm using .pst instead of .xls
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ShowOutlookInstalled {
public static void main(String argv[]) {
try {
Process p = Runtime.getRuntime()
.exec(new String[] { "cmd.exe", "/c", "assoc", ".pst" });
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String extensionType = input.readLine();
input.close();
// extract type
if (extensionType == null) {
outlookNotFoundMessage("File type PST not associated with Outlook.");
} else {
String fileType[] = extensionType.split("=");
p = Runtime.getRuntime().exec(
new String[] { "cmd.exe", "/c", "ftype", fileType[1] });
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String fileAssociation = input.readLine();
// extract path
Pattern pattern = Pattern.compile("\".*?\"");
Matcher m = pattern.matcher(fileAssociation);
if (m.find()) {
String outlookPath = m.group(0);
System.out.println("Outlook path: " + outlookPath);
} else {
outlookNotFoundMessage("Error parsing PST file association");
}
}
} catch (Exception err) {
err.printStackTrace();
outlookNotFoundMessage(err.getMessage());
}
}
private static void outlookNotFoundMessage(String errorMessage) {
System.out.println("Could not find Outlook: \n" + errorMessage);
}
}

Categories