I have a scenario where in we get machine code from one machine that needs to be sent to another but by converting it to string which other machine understands following are the scenarios
**if code is 'AGO PRF' then convert to 'AGO.P'
if code is 'HUSQ A' then convert to 'HUSQ.A'
if code is 'AIK B' then convert to 'AIK.B'
if code is 'ALUS WS' then convert to 'ALUS.WS'
if code is 'VST WSA' then convert to 'VST.WSA'
if code is 'SAB CL' then convert to 'SAB.CL'
if code is 'SPR WSB' then convert to 'NSPR.WSB'
if code is 'AXS PRD CL' then change it to 'AXS.PCL'
if code is 'CTEST RT' then convert to 'CTEST.R'
if code is 'ALUS U' then convert to 'ALUS.U'
if code is 'SFUN WI' then convert to 'SFUN.WI'
if code is 'RQI RT WI' then convert to 'RQI.RTWI'
if code is 'ECA WS WI' then change it to 'ECA.WSWI'.**
I used a MAP to fed in these values as keys and give out the output. but I want to know if there can be more generic solution to this
If there exists neither a rule nor a regularity of the String replacement (I find none), then you need either a mapping table stored in the DB or a static Map<String, String> of these constants:
I recommend the Map in case of a small number of these and they would not be changed often.
I recommend reading from the DB in case of a larger number of these. This also allows you to change the mapping on run with no need to build and redeploy the entire application.
In terms of the data structure, the dictionary-based would be the best way to go - Map<String, String>. It doesn't allow you to store duplicated keys and is simple to use for the transformation:
List<String> listOfStringsToBeReplaced = loadFromSomewhere();
Map<String, String> map = loadFromDb();
List<String> listWithReplacedStrnigs = listOfStringsToBeReplaced.stream()
.map(string -> map.getOrDefault(string, string))
.collect(Collectors.toList());
I use Map::getOrDefault to either replace the value or keep it as is if no mapping is found.
Related
Hello I was creating a Minecraft plugin and was watching a youtube tutorial and explanation on how to store and reclaim data to a yml file this plugin requires the UUID of a player and stores it along with a chunk from the game and the person in the video was using it in an itemstack array Ias apposed to a UUID sting I tried to convert the code to work with a string but it only gave me more errors and was wondering on how to do it so it does not cover tot an array when it is put back into the hashmap
public void restoreClaimedChunks() {
this.getConfig().getConfigurationSection("data").getKeys(false).forEach(key ->{
#SuppressWarnings("unchecked")
UUID[] content = ((List<UUID>) Objects.requireNonNull(this.getConfig().get("data." + key))).toArray(new UUID[0]);
chunks.put(key, content);
});
}
the error I receive when I do this is
incompatible types: java.util.UUID[] cannot be converted to java.util.UUID
and the yml file looks like
ZeradentSMP: zoren3105.zeradentsmp.ZeradentSMP
name: ZeradentSMP
version: 1.0
author: Zoren
Since UUID doesn't implement ConfigurationSerializable the UUIDs in the YAML file are stored as Strings which means a casting error would occur when you try to cast a list of Strings to a list of UUIDs. Try instead getting a list of Strings from the YAML file (either by casting to List<String> or by using ConfigurationSection.getStringList()) and then iterating through to convert each one to a UUID with UUID.fromString().
EDIT
If the error you are receiving is a casting error between UUID[] and UUID then it appears the only thing that could cause that is if the type of the key in the chunks map is UUID and you are trying to put a UUID[] into it.
You can either change the type of the key in the map or don't get a list of UUIDs from the YAML file.
Our C++ software use ITK to write DICOM files. In it we have a Private Tag with LO (Long String) as VR and 2 decimal values as value like 0.3234\0.34223.
The LO choice is inherent to ITK.
In other java application, I use dcm4che3 to read/write them. Since it respects the DICOM protocol, backslash are forbidden, and dcm4che interpret the value as "0.3234" and never reach the second value.
All DICOM viewer applications I use can display this value.
So my question is: Is there a trick in dcm4che to read this complete value as a string "0.3234\0.34223" despite the presence of a backslash?
Below, the code I use:
public DicomInfo uploadFile(MultipartFile file) throws IOException, ParseException {
DicomInfo infos = new DicomInfo();
Attributes attrs = readDicomAttributes(file);
infos.setTags(toAttributesObject(attrs).toString());
}
private static JsonObject toAttributesObject(Attributes targetSeriesAttrs)
{
StringWriter strWriter = new StringWriter();
JsonGenerator gen = Json.createGenerator(strWriter);
JSONWriter writer = new JSONWriter(gen);
writer.write(targetSeriesAttrs);
gen.flush();
gen.close();
return Json.createReader(new
StringReader(strWriter.toString())).readObject();
}
public Attributes readDicomAttributes(MultipartFile file) throws IOException
{
DicomInputStream dis = new DicomInputStream(file.getInputStream());
Attributes dataSet = dis.readDataset(-1, Tag.PixelData);
Attributes fmi = dis.readFileMetaInformation();
dis.close();
fmi.addAll(dataSet);
return fmi;
}
In the JSON I get for this tag:
\"00110013\":{\"vr\":\"LO\",\"Value\":[\"0.4323\"]},
As you can see it is LO and the second part is already lost.
The method I use to get the specific attribute:
attr.getStrings(0x00110013)
send back a table with only one value, 0.4323.
The problem happens during the readDataSet function.
When I open tags with software like free dicom viewer, I have the complete data, so data is here.
Ok I found the source of the problem... It is the addAll fmi.addAll(dataSet);
In dataSet, getStrings works perfectly. In fmi after addAll, the attributes lost the second value.
So my problem is to solve this addAll issue now: dcm4che3 java lib: Attributes.addAll method seems to lost multiple LO values
See answer from Paolo, and please believe us that the backslash is not a violation of the VR. Like he said, the attribute is 2-dimensional, i.e. it has two values of VR LO which are separated by the backslash.
I know a bit about the dcm4che project and the people behind it, and it is nearly unthinkable to me that it is generally incapable of handling this.
I strongly suspect that your problem is related to the fact that your attribute is private. That is, without any additional information to the tag and its value, dcm4che (and any other product) can never know that the attribute's value is encoded as VR LO (Long String).
The default transfer syntax in DICOM is Implicit Little Endian. This means, that the dataset does not convey an explicit information about the VR of the attributes in the dataset. This information is implicitly encoded by the Tag of the attribute, and the data dictionary (DICOM Part 6) must be used to look up the tag and obtain the corresponding VR. Obvioulsy this only works for well-known DICOM tags defined in the standard and fails for private ones.
So one option is to try encoding the dataset in Explicit Little Endian, which means that the VR is part of the attribute's encoding in the dataset. I would expect this to be sufficient.
Mature toolkits (like dcm4che) allow for extending the data dictionary by configuration, that is, you can extend the "official" data dictionary used by the tookit with your custom tag definitions - including the VR. So the tag can be looked up in the case that the VR is not explicitly given in the dataset itself.
Again, I am not an expert for dcm4che, but a quick search at google for "dcm4che private dictionary" yields this promising link.
I am more than confident that you can solve the problem in dcm4che and that you do not have to migrate to a different toolkit.
The solution of this problem is to write
dataSet.addAll(fmi);
return dataSet;
instead of
fmi.AddAll(dataSet);
return fmi;
since the addAll methods lost multiple values of private LO
LO can have multiple values separated by a backslash.
The DICOM standard says that in the VR "LO" the backslash cannot be used in values because it is used to separate the different elements.
In VRs that don't allow multiple elements then the backslash can be used in values.
So dcm4che is wrong here.
I was trying to insert Strings into StringBuffer using foreach method of parallelStream(), created from a Set collection.
The problem is every time I execute the code, the final String (StringBuffer.toString()) has 1 less element of the total (random element every time I try).
I also change the StringBuffer to StringBuilder, the parallelStream() to stream(), but always has 1 less element.
I am using:
- Java version: java 1.8_121
- Server: Weblogic 12.2.1.2 (I don't think this is relevant to the problem)
- Spring boot 2.0.2.RELEASE (I don't think this is relevant to the problem)
NOTE: I used a Map to keep the pdfs I should sign later on the process (in another HTTP request).
Map<String, ClientPdf> dataToEncript = new HashMap<>(); // pdf name it will be the key for this map (it is unique in the sql query)
List<Client> listClients = // list of clients from database
Set<ClientPdf> clientsPdf = new HashSet<>();
for (Client client : listClients) {
clientsPdf.add(client.clientPdf()); // clientPdf() generate a new object ClientPdf, which is similar to Client class, but with less fields (essential for the Set)
}
log.debug("Generating documents");
clientsPdf.parallelStream().forEach(pdf -> {
// some code to generate pdf
log.debug("Inserting pdf: {}", pdf); // this log print, for example, 27.000 lines
dataToEncript.put(pdf.getPdfName(), pdf);
});
StringBuffer sb = new StringBuffer(); // StringBuffer or StringBuilder, the same problem
for (ClientPdf clientPdf : dataToEncript.values()) {
sb.append(clientPdf.getPdfName() + ";" + clientPdf.getRut() + "\n"); // appending all values of de map dataToEncript, it will append 26.669 (1 less)
}
clientsPdf.parallelStream().forEach(pdf -> {
// ...
dataToEncript.put(pdf.getPdfName(), pdf);
});
dataToEncript is not a thread-safe data structure, so this is likely to cause ridiculous and weird bugs like the one you're observing
In general, using forEach is often a bad sign, and you should almost always be using a Collector or some other method. For example, here you should probably use
clientsPdf.parallelStream()
.collect(Collectors.toConcurrentMap(Pdf::getPdfName, pdf -> pdf));
to get a correct map out.
Even better, you could write
clientsPdf.parallelStream()
.map(clientPdf -> clientPdf.getPdfName() + ";" + clientPdf.getRut() + "\n")
.collect(Collectors.joining())
to get the final String out without any manual management of StringBuffer or the like.
Because HashMap is not thread-safe as Wasserman mentioned above.
It may cause an inconsistency in the state of HashMap if multiple threads are accessing the same object and try to modify its structure.
Therefore, HashTable, SynchronizedMap or ConcurrentHashMap are introduced to use HashMap in multi-thread environment (such as parallelStream()).
You can simply rewrite the first row of your code as follows:
Map<String, ClientPdf> dataToEncript = Collections.synchronizedMap(new HashMap<>());
Now, you are supposed to get the correct result after rerunning your program.
BTW, both HashTable and SynchronizedMap are not good in performance, you can use ConcurrentHashMap instead to overcome this issue.
Good luck!
I made a simple client call to the XML-RPC WordPress API/Posts using a xml-rpc client and according to their documentation here it returns a struct. How can i access the return values.
Here is a look at my code:
XmlRpcClient client = new XmlRpcClient("http://www.mywebsite.net/xmlrpc.php", false);
String[] fields = new String[4];
fields[0] = "post_id";
fields[1] = "post_title";
fields[2] = "post_date";
fields[3] = "post_content";
Object token = client.invoke("wp.getPost", new Object[]{"0","myusername", "mypassword", 1545, fields });
System.out.println(token);
When I print use
System.out.println(token);
I get the following out put:
{item_one=I am item number one, item_two=I am Item two...}
How can I access item_one and item_two?
There's a bit of information missing (what's the fully qualified name of XmlRpcClient?), but assuming that client.invoke actually returns just an Object and not something more specific that has accessor methods, you can parse the response using something like this:
Object token = client.invoke("wp.getPost", new Object[]{"0","myusername", "mypassword", 1545, fields });
String[] items = token.toString().split(",");
for (String item : items) {
String[] parts = item.split("=");
String key = parts[0];
String value = parts[1];
// do stuff with your keys and values here
}
Of course this isn't perfect code -- you may need to check for nulls, use String.trim(), etc, but it should get you started.
You don't have a true Java representation of the data returned, in that you don't have an object on which you can access
token.item_one
rather you have a string containing a representation of a set - that is something that (in concept) from which you could retrieve an value by its name
token.get("item_one")
This string format is probably JSON, which pretty much looks like JavaScript, and hence can represent quite complex data. In general you can have arrays of objects and objects containing objects (for example, a Customer might contain an Address object)
So you have two possibilities:
1). parse the string into a true Java representation such as one of the standard Java collection classes. You then use the get-by-name style I show above.
2). define a Java class that mimics the structure of the data and then parse the string to fill out such an object, you can then use the "dot" form of access - you really have a Java Object representing the data.
In the first case there are suitable libraries such as quickJson
For the second you can use implementations of standards such as JAX/B, which tends to be more work as you may need to construct the target Java Class by hand. Enterprise Java runtimes will give you these facilities and perhaps tooling to help, or look at implementaitons such as Jackson. You will see that JAX/B hada focus on mapping from XML to Java, but tutorials such as this show how to work with JSON instead.
My guess is that the first option, simple parsing to a collection may be enough for you.
I have some torrent file with list of announce urls, f.e. this is the part of it:
announce-listll68:http://iptorrents.com:2790/b6d18a815ab4421a86de672d6833369d/announceel67:http://iptorrents.me:2710/b6d18a815ab4421a86de672d6833369d/announceel67:http://iptorrents.ru:6969/b6d18a815ab4421a86de672d6833369d/announceee
So here is one array with key «announce-list» which contains three elements (bencoded data, http://en.wikipedia.org/wiki/Bencode).
So I am using BDecoder.java class from Aeltis to decode it. While parsing I am getting the next values of Map:
{created by=[B#141d683, announce=[B#16a55fa, encoding=[B#32c41a, announce-list=[[[B#e89b94], [[B#13e205f], [[B#1bf73fa]], comment=[B#5740bb, creation date=1310060702, info={pieces=[B#5ac072, name=[B#109a4c, length=34209795, piece length=65536, private=1}}
So announce list filled with some hashes. So how can I convert it to normal string (such as «http://iptorrents.com:2790/b6d18a815ab4421a86de672d6833369d/announce»)? Or it's some algorithm issue in BDecoder.java?
This is the method of upper class to decode data: http://pastebin.com/HimqF0ye
The object returned in your case is a generic Map, with no type defined. So I suppose when you try to print the values, only the addresses are printed. Try casting the values of the Map to String and that should do the trick.
Best regards,
Baptiste