Java iTunes COM interface Jacob - Get PersistentIDs (PersistentIDLow and PersistentIDHigh) - java

I have some problems to understand the iTunes COM interface with Jacob in reference to the PersistentIDs (PersistentIDLow and PersistentIDHigh) to identify playlists and tracks by unique key in iTunes.
I hope someone can tell me what I'm doing wrong.
Here is my code example to read one playlist List 1 of iTunes.
The example shows in comments the trial to read the PersistentIDs for the playlist List 1 and for every track of the playlist.
But the Dispatch doesn't work, see code lines with comment "doesn't work".
Exception in thread "main" com.jacob.com.ComFailException: Can't map
name to dispid: GetObjectPersistentIDLow
Exception in thread "main" com.jacob.com.ComFailException: Can't map name to dispid: GetObjectPersistentIDHigh
public static void main(String args[]){
System.setProperty("jacob.dll.path", "C:\\Dev\\iTunesTest\\dll\\jacob-1.18-M2-x86.dll");
// build iTunes activeX component
ActiveXComponent g_iTunes = new ActiveXComponent("iTunes.Application");
// get iTunes Sources
Dispatch g_sources = Dispatch.call(g_iTunes, "Sources").toDispatch();
// determine iTunes Library Source ID
int sourceID = 0;
for (int i=1;i<=Dispatch.get(g_sources, "Count").getInt();i++){
Dispatch itemSearch = Dispatch.call(g_sources, "Item", i).toDispatch();
if (ITunesSourceKind.values()[Dispatch.get(itemSearch, "Kind").getInt()].toString().equals("ITSourceKindLibrary")){
sourceID = Dispatch.get(itemSearch, "Index").getInt();
}
itemSearch.safeRelease();
}
// get iTunes Library Source
Dispatch g_source = Dispatch.call(g_sources, "Item", sourceID).toDispatch();
// get iTunes Playlists
Dispatch g_playlists = Dispatch.get(g_source, "Playlists").toDispatch();
// get iTunes Playlist byName
Dispatch g_playlistItem = Dispatch.call(g_playlists, "ItemByName", "List 1").toDispatch();
// get iTunes Tracks for Playlist
Dispatch g_tracks = Dispatch.get(g_playlistItem, "Tracks").toDispatch();
String name = Dispatch.get(g_playlistItem, "Name").getString();
System.out.println("Playlist: " + name);
// doesn't work
System.out.println("ID Low : " + Dispatch.call(g_playlistItem, "GetObjectPersistentIDLow").getLong());
System.out.println("ID High : " + Dispatch.call(g_playlistItem, "GetObjectPersistentIDHigh").getLong());
// get every iTunes playlist track
int playlistSongCount = Dispatch.get(g_tracks, "Count").getInt();
for (int i=1; i<=playlistSongCount; i++){
// get single iTunes playlist track
Dispatch track = Dispatch.call(g_tracks, "Item", i).toDispatch();
System.out.println(" Song Name: " + Dispatch.get(track, "Name").getString());
// doesn't work
System.out.println(" ID Low : " + Dispatch.call(track, "GetObjectPersistentIDLow").getLong());
System.out.println(" ID High : " + Dispatch.call(track, "GetObjectPersistentIDHigh").getLong());
if(track != null){
track.safeRelease();
}
}
// release objects
if(g_tracks != null){
g_tracks.safeRelease();
}
if(g_playlistItem != null){
g_playlistItem.safeRelease();
}
if(g_playlists != null){
g_playlists.safeRelease();
}
if(g_source != null){
g_source.safeRelease();
}
if(g_sources != null){
g_sources.safeRelease();
}
if(g_iTunes != null){
// close iTunes
//g_iTunes.invoke("Quit");
g_iTunes.safeRelease();
}
}
I thought this should work, see reference url Java-iTunes-API
Summary:
/**
* Returns the high 32 bits of the persistent ID of the specified IITObject.
* See the documentation on IITObject for more information on persistent
* IDs.
*
* The object may be a source, playlist, or track.
*
* #param iObject
* The object to fetch the High Persistent ID.
* #return The high 32 bits of the 64-bit persistent ID.
*/
public long getITObjectPersistentIDHigh(ITObject iObject) {
Dispatch object = iObject.fetchDispatch();
return Dispatch.call(object, "GetObjectPersistentIDHigh", object)
.getLong();
}
/**
* Returns the low 32 bits of the persistent ID of the specified IITObject.
* See the documentation on IITObject for more information on persistent
* IDs.
*
* The object may be a source, playlist, or track.
*
* #param iObject
* The object to fetch the Low Persistent ID.
* #return The low 32 bits of the 64-bit persistent ID.
*/
public long getITObjectPersistentIDLow(ITObject iObject) {
Dispatch object = iObject.fetchDispatch();
return Dispatch.call(object, "GetObjectPersistentIDLow", object)
.getLong();
}
Any idea what I'm doing wrong?
Thank you so much.
Michael

Related

How to scan/load all the files from Internal and External storage in android 10 and android 11

In android 10 and in android 11 how to load all files from internal and external storage. Actually I want to load a specific extension files (i.e.pdf, txt) within my app, either the specific extension file is saved in internal or external storage.
I have used the following code which is working fine upto android 8.1 API Level 26
I have taken the StorageUtil class from internet, which will load all the possible physical path
public class StorageUtil {
// Primary physical SD-CARD (not emulated)
private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE");
// All Secondary SD-CARDs (all exclude primary) separated by File.pathSeparator, i.e: ":", ";"
private static final String SECONDARY_STORAGES = System.getenv("SECONDARY_STORAGE");
// Primary emulated SD-CARD
private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET");
// PhysicalPaths based on phone model
#SuppressLint("SdCardPath")
#SuppressWarnings("SpellCheckingInspection")
private static final String[] KNOWN_PHYSICAL_PATHS = new String[]{
"/storage/sdcard0",
"/storage/sdcard1", //Motorola Xoom
"/storage/extsdcard", //Samsung SGS3
"/storage/sdcard0/external_sdcard", //User request
"/mnt/extsdcard",
"/mnt/sdcard/external_sd", //Samsung galaxy family
"/mnt/sdcard/ext_sd",
"/mnt/external_sd",
"/mnt/media_rw/sdcard1", //4.4.2 on CyanogenMod S3
"/removable/microsd", //Asus transformer prime
"/mnt/emmc",
"/storage/external_SD", //LG
"/storage/ext_sd", //HTC One Max
"/storage/removable/sdcard1", //Sony Xperia Z1
"/data/sdext",
"/data/sdext2",
"/data/sdext3",
"/data/sdext4",
"/sdcard1", //Sony Xperia Z
"/sdcard2", //HTC One M8s
"/storage/microsd" //ASUS ZenFone 2
};
/**
* Returns all available storages in the system (include emulated)
* <p/>
* Warning: Hack! Based on Android source code of version 4.3 (API 18)
* Because there is no standard way to get it.
*
* #return paths to all available storages in the system (include emulated)
*/
public static String[] getStorageDirectories(Context context) {
// Final set of paths
final Set<String> availableDirectoriesSet = new HashSet<>();
if (!TextUtils.isEmpty(EMULATED_STORAGE_TARGET)) {
// Device has an emulated storage
availableDirectoriesSet.add(getEmulatedStorageTarget());
} else {
// Device doesn't have an emulated storage
availableDirectoriesSet.addAll(getExternalStorage(context));
}
// Add all secondary storages
Collections.addAll(availableDirectoriesSet, getAllSecondaryStorages());
String[] storagesArray = new String[availableDirectoriesSet.size()];
return availableDirectoriesSet.toArray(storagesArray);
}
private static Set<String> getExternalStorage(Context context) {
final Set<String> availableDirectoriesSet = new HashSet<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Solution of empty raw emulated storage for android version >= marshmallow
// because the EXTERNAL_STORAGE become something like: "/Storage/A5F9-15F4",
// so we can't access it directly
File[] files = getExternalFilesDirs(context, null);
for (File file : files) {
if (file != null) {
String applicationSpecificAbsolutePath = file.getAbsolutePath();
String rootPath = applicationSpecificAbsolutePath.substring(
0,
applicationSpecificAbsolutePath.indexOf("Android/data")
);
availableDirectoriesSet.add(rootPath);
}
}
} else {
if (TextUtils.isEmpty(EXTERNAL_STORAGE)) {
availableDirectoriesSet.addAll(getAvailablePhysicalPaths());
} else {
// Device has physical external storage; use plain paths.
availableDirectoriesSet.add(EXTERNAL_STORAGE);
}
}
return availableDirectoriesSet;
}
private static String getEmulatedStorageTarget() {
String rawStorageId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// External storage paths should have storageId in the last segment
// i.e: "/storage/emulated/storageId" where storageId is 0, 1, 2, ...
final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
final String[] folders = path.split(File.separator);
final String lastSegment = folders[folders.length - 1];
if (!TextUtils.isEmpty(lastSegment) && TextUtils.isDigitsOnly(lastSegment)) {
rawStorageId = lastSegment;
}
}
if (TextUtils.isEmpty(rawStorageId)) {
return EMULATED_STORAGE_TARGET;
} else {
return EMULATED_STORAGE_TARGET + File.separator + rawStorageId;
}
}
private static String[] getAllSecondaryStorages() {
if (!TextUtils.isEmpty(SECONDARY_STORAGES)) {
// All Secondary SD-CARDs split into array
return SECONDARY_STORAGES.split(File.pathSeparator);
}
return new String[0];
}
/**
* Filter available physical paths from known physical paths
*
* #return List of available physical paths from current device
*/
private static List<String> getAvailablePhysicalPaths() {
List<String> availablePhysicalPaths = new ArrayList<>();
for (String physicalPath : KNOWN_PHYSICAL_PATHS) {
File file = new File(physicalPath);
if (file.exists()) {
availablePhysicalPaths.add(physicalPath);
}
}
return availablePhysicalPaths;
}
/**
* Returns absolute paths to application-specific directories on all
* external storage devices where the application can place persistent files
* it owns. These files are internal to the application, and not typically
* visible to the user as media.
* <p>
* This is like {#link Context#getFilesDir()} in that these files will be
* deleted when the application is uninstalled, however there are some
* important differences:
* <ul>
* <li>External files are not always available: they will disappear if the
* user mounts the external storage on a computer or removes it.
* <li>There is no security enforced with these files.
* </ul>
* <p>
* External storage devices returned here are considered a permanent part of
* the device, including both emulated external storage and physical media
* slots, such as SD cards in a battery compartment. The returned paths do
* not include transient devices, such as USB flash drives.
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
* most available space, as measured by {#link android.os.StatFs}.
* <p>
* Starting in {#link Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
* the calling app. Before then,
* {#link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to
* write. Write access outside of these paths on secondary external storage
* devices is not available. To request external storage access in a
* backwards compatible way, consider using {#code android:maxSdkVersion}
* like this:
*
* <pre class="prettyprint"><uses-permission
* android:name="android.permission.WRITE_EXTERNAL_STORAGE"
* android:maxSdkVersion="18" /></pre>
* <p>
* The first path returned is the same as
* {#link Context#getExternalFilesDir(String)}. Returned paths may be
* {#code null} if a storage device is unavailable.
*
* #see Context#getExternalFilesDir(String)
*/
private static File[] getExternalFilesDirs(Context context, String type) {
if (Build.VERSION.SDK_INT >= 19) {
return context.getExternalFilesDirs(type);
} else {
return new File[]{context.getExternalFilesDir(type)};
}
}
And loadDirectoryFiles function which will load all the files within specific directory
object LoadDirectory {
fun loadDirectoryFiles(directory: File) {
try {
val fileList: Array<File> = directory.listFiles()
if (fileList.isNotEmpty()) {
for (i in fileList.indices) {
if (fileList[i].isDirectory) {
loadDirectoryFiles(fileList[i])
} else {
val name: String = fileList[i].name.toLowerCase(Locale.getDefault())
//Now look for desired extension
if (name.endsWith(Constants.PDF_EXTENSION)) {
Constants.allFileList.add(fileList[i])
}
}
}
}
}
catch (e : Exception){
Log.d("TAG","Error: ${e.message} and directory: ${directory.absoluteFile}")
}
}
}
and here its usage
val storagePaths = StorageUtil.getStorageDirectories(this)
for (path in storagePaths) {
val storageFile = File(path)
LoadDirectory.loadDirectoryFiles(storageFile)
}
The above code is working fine upto android 8.1 but is not working on above android 8.1, Now how to achieve this by loading a specific extension (i.e. pdf) files from internal and external storage
Thanks in advance for helping me

Track-mate unique bar-code reading

I have a program that I want to run on track-mate
Track-mate system identifies the object through the webcam which is connected to the PC. We place the webcam under the Plexiglas sheet (a transparent surface which is save for children) to track the bar-code and returns a digital feedback to the Track-mate...
the bar-code is saved in a database in a String format but our problem is that the bar-code readings are different each time we move the object on the surface, which makes it not unique for the exact object.
what can we do to solve this problem?
The program sources:
//LusidOSC a layer that reads tags from a webcam and send the result to any application
public LusidOSCJavaApp(){
// create the client, on port 3333.
lusidClient = new LusidClient(this, 3333);
System.out.println("lusid osc java app ");
System.out.println(View.getisRunning());
while(View.getisRunning()){//SOME CODE TO DO}
// ---------------------------------------------------------------
// these methods are called whenever a LusidOSC event occurs.
// called when an object is added to the scene
public void addLusidObject(LusidObject lObj) {
System.out.println("add lusid object");
//when object is added we add an instance of the object to lusidObj arraylist
lusidArr.add(lObj);
//The problem is here because the ID isn't unique (but it should be unique...)
if(lObj.getUniqueID().equals("0x111111AA1111")) {
System.out.println("you put the right shape");}
else{
System.out.println("error");}
System.out.println("add object: "+lObj.getUniqueID());
System.out.println(" location =
("+lObj.getX()+","+lObj.getY()+","+lObj.getZ()+")");
System.out.println(" rotation =
("+lObj.getRotX()+","+lObj.getRotY()+","+lObj.getRotZ()+")");
System.out.println("data =
("+lObj.getEncoding()+","+lObj.getData()+")");
System.out.println("#######################################");
System.out.println(lusidArr.size());
}
// called when an object is removed from the scene
public void removeLusidObject(LusidObject lObj) {
lusidArr.remove(lObj);
System.out.println("remove object: "+lObj.getUniqueID());
}
// called when an object is moved
public void updateLusidObject (LusidObject lObj) {
//System.out.println("update object: "+lObj.getUniqueID());
ArrayList<LusidObject> currentLusidList = new ArrayList<LusidObject>
(Arrays.asList(lusidClient.getLusidObjects()));
Download Link + source: Trackmate

Error 110 while running make

I'm getting the following error:
frameworks/base/core/java/android/os/mypackage/MyServiceListenerClass.java:283: error 110: Parameter of unavailable type android.os.storage.VolumeInfo in android.os.mypackage.MyServiceListenerClass.myMethod()
I have created a new package with some classes and those classes use VolumeInfo from the storage package.
I couldn't find any documentation on this error. What have I done wrong?
UPDATE:
Found out that Error 110 = UNAVAILABLE_SYMBOL.
Found this section in doclava/Stubs.java:
for (ParameterInfo p : m.parameters()) {
TypeInfo t = p.type();
if (!t.isPrimitive()) {
hiddenClass = findHiddenClasses(t);
if (null != hiddenClass) {
if (hiddenClass.qualifiedName() == t.asClassInfo().qualifiedName()) {
// Parameter type is hidden
Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(),
"Parameter of unavailable type " + t.fullName() + " in " + cl.qualifiedName()
+ "." + m.name() + "()");
} else {
// Parameter type contains a generic parameter
Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(),
"Parameter uses type parameter of unavailable type " + t.fullName() + " in "
+ cl.qualifiedName() + "." + m.name() + "()");
}
}
}
}
So the reason for this error was the #hide attribute at the bottom of VolumInfo's documentation part:
/**
* Information about a storage volume that may be mounted. A volume may be a
* partition on a physical {#link DiskInfo}, an emulated volume above some other
* storage medium, or a standalone container like an ASEC or OBB.
* <p>
* Volumes may be mounted with various flags:
* <ul>
* <li>{#link #MOUNT_FLAG_PRIMARY} means the volume provides primary external
* storage, historically found at {#code /sdcard}.
* <li>{#link #MOUNT_FLAG_VISIBLE} means the volume is visible to third-party
* apps for direct filesystem access. The system should send out relevant
* storage broadcasts and index any media on visible volumes. Visible volumes
* are considered a more stable part of the device, which is why we take the
* time to index them. In particular, transient volumes like USB OTG devices
* <em>should not</em> be marked as visible; their contents should be surfaced
* to apps through the Storage Access Framework.
* </ul>
*
* #hide
*/
Removing it solves the issue.

Apache Commons - NNTP - "Article To List" - AWT

I am currently using Apache Commons Net to develop my own NNTP reader. Using the tutorial available I was able to use some of their code to allow me to get articles back.
The Code I am using from NNTP Section -
System.out.println("Retrieving articles between [" + lowArticleNumber + "] and [" + highArticleNumber + "]");
Iterable<Article> articles = client.iterateArticleInfo(lowArticleNumber, highArticleNumber);
System.out.println("Building message thread tree...");
Threader threader = new Threader();
Article root = (Article)threader.thread(articles);
Article.printThread(root, 0);
I need to take the articles and turn them into a List type so I can send them to AWT using something like this -
List x = (List) b.GetGroupList(dog);
f.add(CreateList(x));
My Entire code Base for this section is -
public void GetThreadList(String Search) throws SocketException, IOException {
String hostname = USE_NET_HOST;
String newsgroup = Search;
NNTPClient client = new NNTPClient();
client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
client.connect(hostname);
client.authenticate(USER_NAME, PASS_WORD);
if(!client.authenticate(USER_NAME, PASS_WORD)) {
System.out.println("Authentication failed for user " + USER_NAME + "!");
System.exit(1);
}
String fmt[] = client.listOverviewFmt();
if (fmt != null) {
System.out.println("LIST OVERVIEW.FMT:");
for(String s : fmt) {
System.out.println(s);
}
} else {
System.out.println("Failed to get OVERVIEW.FMT");
}
NewsgroupInfo group = new NewsgroupInfo();
client.selectNewsgroup(newsgroup, group);
long lowArticleNumber = group.getFirstArticleLong();
long highArticleNumber = lowArticleNumber + 5000;
System.out.println("Retrieving articles between [" + lowArticleNumber + "] and [" + highArticleNumber + "]");
Iterable<Article> articles = client.iterateArticleInfo(lowArticleNumber, highArticleNumber);
System.out.println("Building message thread tree...");
Threader threader = new Threader();
Article root = (Article)threader.thread(articles);
Article.printThread(root, 0);
try {
if (client.isConnected()) {
client.disconnect();
}
}
catch (IOException e) {
System.err.println("Error disconnecting from server.");
e.printStackTrace();
}
}
and -
public void CreateFrame() throws SocketException, IOException {
// Make a new program view
Frame f = new Frame("NNTP Reader");
// Pick my layout
f.setLayout(new GridLayout());
// Set the size
f.setSize(H_SIZE, V_SIZE);
// Make it resizable
f.setResizable(true);
//Create the menubar
f.setMenuBar(CreateMenu());
// Create the lists
UseNetController b = new UseNetController(NEWS_SERVER_CREDS);
String dog = "*";
List x = (List) b.GetGroupList(dog);
f.add(CreateList(x));
//f.add(CreateList(y));
// Add Listeners
f = CreateListeners(f);
// Show the program
f.setVisible(true);
}
I just want to take my list of returned news articles and send them to the display in AWT. Can any one explain to me how to turn those Articles into a list?
Welcome to the DIY newsreader club. I'm not sure if you are trying to get a list of newsgroups on the server, or articles.You have already have your Articles in an Iterable Collection. Iterate through it appending what you want in the list from each article. You probably aren't going to want to display the whole article body in a list view. More likely the message id, subject, author or date (or combination as a string). For example for a List of just subjects:
...
Iterable<Article> articles = client.iterateArticleInfo(lowArticleNumber, highArticleNumber);
Iterator<Article> it = articles.iterator();
while(it.hasNext()) {
Article thisone = it.next();
MyList.add(thisone.getSubject());
//MyList should have been declared up there somewhere ^^^ and
//your GetThreadList method must include List in the declaration
}
return MyList;
...
My strategy has been to retrieve the articles via an iterator in to an SQLite database with the body, subject, references etc. stored in fields. Then you can create a list sorted just how you want, with a link by primary key to retrieve what you need for individual articles as you display them. Another strategy would be an array of message_ids or article numbers and fetch each one individually from the news server as required. Have fun - particularly when you are coding for Android and want to display a list of threaded messages in the correct sequence with suitable indents and markers ;). In fact, you can learn a lot by looking at the open source Groundhog newsreader project (to which I am eternally grateful).
http://bazaar.launchpad.net/~juanjux/groundhog/trunk/files/head:/GroundhogReader/src/com/almarsoft/GroundhogReader

Java System.getProperty("user.home") directory missing separator

Whenever a user enters "~" as an argument, my program replaces it with System.getProperty("user.home").
After debugging, I see that this replaces "~" with "C:UsersSoulBeaver" and not "C:/Users/SoulBeaver".
Going through previous questions about incorrect user.home folders, I found out that Java tries to fetch the path from
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\
However, I'm using Windows 8 and there is seemingly nothing wrong:
At this point I'm assuming Java "eats" the backslash... so how do I prevent that from happening?
Update
Since the code was requested, here it is. This is taken from Allen Holub's Solving Java's Configuration Problem
/**
* For every enum element in the array, treat keys[i].name() as a key
* and load the associated value from the following places (in order):
*
* <ol>
* <li>a -D command-line switch (in System properties)</li>
* <li>if no -D value found, an environment variable with the same name as the key</li>
* <li>if no environment found, the default stored in the Enum element itself</li>
* </ol>
*
* That value must identify an existing directory in the file system, and a
* File representing that location can be retrieved from {#link #directory(Enum)}.
*
* #param keys The values() array associated with the enum that's using this class.
* #throws IllegalStateException if a given key doesn't have a value associated with it
* or if that value doesn't identify an existing directory.
*/
public LocationsSupport(T[] keys) throws IllegalStateException {
StringBuilder logMessage = new StringBuilder("Loaded environment/-D properties:\n");
try {
for (T element : keys) {
String how = "???";
String key = element.name();
String value;
if ((value = System.getProperty(key)) != null)
how = "from system property (-D)";
else if ((value = System.getenv(key)) != null)
how = "from environment";
else if ((value = element.defaultValue()) != null)
how = "from default. Mapped from: " + value;
if (value != null)
value = value.replaceAll("~", System.getProperty("user.home"));
if (value == null || value.isEmpty())
throw new IllegalStateException("Value for " +key +" cannot be null or empty.");
File location = new File(value);
createLocationIfNecessary(location, element.createIfNecessary());
if (!location.isDirectory())
throw new IllegalStateException("Location specified in "
+key
+" (" +asString(location) +") "
+"does not exist or is not a directory.");
dictionary.put(key, location);
logMessage.append("\t");
logMessage.append(key);
logMessage.append("=");
logMessage.append(asString(location) );
logMessage.append(" (");
logMessage.append(how);
logMessage.append(")\n");
}
} finally {
if (log.getAllAppenders() instanceof NullEnumeration)
System.err.println(logMessage);
else
log.info(logMessage);
}
}
It's failing at trying to locate the default location for CONFIG:
public enum Places implements Locations {
CONFIG ("~/config"),
HOME ("~"),
TMP ("~/tmp", true),
TERM_STORE ("~/tmp/indices/term_store/", true),
RESOURCE_STORE ("~/tmp/indices/resource_store/", true),
PERSON_STORE ("~/tmp/indices/person_store/", true);
I am using Java 1.7.0_13 and IntelliJ IDEA 12.1.3
You are using regular expression based replacement. In the replacement pattern for java regexes, the '\' character is special. you need to pass the user home dir through Matcher.quoteReplacement() before using it as a replacement pattern (as covered in the javadoc for the relevant method).
may be following can give some info.
Bug
Discussion

Categories