I'm using ASM4 for some Java bytecode manipulation. I want to copy some code from one method to another one. The latter has some additional code and because of that every LabelNode from the first method must be remapped.
The problem arise when local variables needs to be inserted. I followed this pattern: get the local variables from first method, create a copy of it with index and start label and ending label nodes modified. The visitor used to get the local variable has this form:
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index)
and the code that should insert a new local variable look like this:
localVariableList.add(new LocalVariableNode((String name, String desc, String signature, LabelNode start, LabelNode end, int index)))
Problem is, the info field from Label object is null, therefore I can't get a reference of the old LabelNode so that I could remap with my new label nodes.
I also tried to get the offset from the code with label.getOffset() and then remap the offset to a list of offsets associated with my new list of LabelNode but I get an exception:
java.lang.IllegalStateException: Label offset position has not been resolved yet
at org.objectweb.asm.Label.getOffset(Unknown Source)
If any of you has an idea of how could I get the corresponding LabelNode from a Label would be much appreciated.
Or maybe there's a better approach on copying the code from one method to another one and resolving the issue with labels, lablenode's and localvariables.
Most of the time I use the tree API because of it's simplicity.
Thank for you help.
There is an example of similar transformation in "Inline Method" section of my AOSD'07 paper.
Related
I'm struggling with a little Java Project:
I made a Program which autofills a PDF Formular. Mostly everything works fine for me, but there is a Problem: In this PDF Formular (which is given from my company, so I have to deal with this document) is a equation Field, which is used for calculation the Costs from Number of Items and the single Price. When I insert the Price of a single Item as a String to my PDF
public void setEinzelpreis(String Einzelpreis)
{
try {
fieldList.get(30).setValue(Einzelpreis);
...
There should be the single Price on the empty field in the first row. The last Cell of the row is auto-calculated by the pdf.
When I Click in the PDF in the "empty" Field, the Value appears:
When I click to another Field, the Value disappears. This is my Problem.
I'm getting the FieldList via pdfbox and the Code for getting my fieldList of the PFD is:
try {
pdfTemplate = PDDocument.load(template);
PDDocumentCatalog docCatalog = pdfTemplate.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
if (acroForm != null)
{
// Get field names
fieldList = acroForm.getFields();
}
...
So, can anybody tell what I'm doing wrong? Maybe the PDF wants a double Value for the equation and I am giving a String? But I don't know how to write a double in the FieldList. Thanks a lot for every hint!
Edit:
The PDF File which I'm using:
https://1drv.ms/b/s!Av6exjPNXlgOioouAuXL6QV4eUGkqg?e=ocfhvC
And this is the file I generated:
https://1drv.ms/b/s!Av6exjPNXlgOioovK-HuRuXW2aRy_w?e=D1ZCA8
The strange thing is: when I change the value in the document by hand, everything acts normal, even with a different Document Viewer.
First of all, the AcroForm form structure in your PDF is weird. It looks like someone used a graphical form generation tool he did not understand and clicked, dragged, dropped, copied, ... until the form in a viewer did what he wanted, not caring about it having become difficult to maintain.
In particular the Einzelpreis fields have a completely unnecessary structure of intermediate and final fields, e.g.
Thus, the field Einzelpreis in € exkl USt1 (the '€' is missing in the tree above) is not the one to fill in, it's merely an intermediary field. The actual form field to fill in is Einzelpreis in € exkl USt1.0.0.0.0.
Unfortunately you in your code simply grab the 30th field in the field list returned by PDAcroForm, and this field happens to be the intermediary field Einzelpreis in € exkl USt1; as an intermediary field it has no visible widgets of its own, so your setValue call doesn't change the visible Einzelpreis.
The JavaScript instruction calculating the Gesamtpreis uses the value from the final field, too:
AFSimple_Calculate("PRD", new Array ("Anzahl1", "Einzelpreis in € exkl USt1.0.0.0.0"));
But as the field value is inheritable and none of the .0 fields has an own value, the calculation sees the 100 once form calculation has been triggered and uses it.
Thus, you should fill the Einzelpreis in € exkl USt1.0.0.0.0 field instead. And the more secure way to retrieve it is not by index in a field list but by name:
PDField fieldByName = acroForm.getField("Einzelpreis in € exkl USt1.0.0.0.0");
(excerpt from FillInForm test testFill2020_04BeschaffungsantragEinzelpreis)
After filling that field, the "100" should be visible in your form.
The remaining problem that the Gesamtpreis value is not calculated is due to the fact already mentioned by #Tilman in a comment to the question: PDFBox doesn't use javascript. Thus, you have to calculate those values yourself and update the fields in question accordingly.
If you need to know the correct name of a form field, you can do as Tilman proposed and use the PDFBox PDFDebugger. If you hover over the field there, it will display the name in the status bar at the bottom.
By the way, the AcroForm method getFields won't return the field required here anyways. As documented in its JavaDocs, this method will return all of the documents root fields, no fields further down in the hierarchy, at least not immediately. (From the user perspective the method name getFields is a misnomer. It is accurate, though, from the PDF specification perspective as the corresponding entry in the AcroForms object has the key Fields.)
Beware, though, you probably will have to update your PDFBox version. In earlier versions PDFBox did not update appearances of fields with JavaScript actions (believing some JavaScript would fill it in anyways). I used the current 3.0.0-SNAPSHOT in which that behavior has been changed.
i create hash table in java but there is aproblem in it when adding elements in it.
Hashtable <Integer,String> hashT=new Hashtable<Integer ,String >();
hashT.put<sum2 , g>;
the error in second line where define sum2 is variable contain integer value and g variable contain string value. i dont know where the problem in putting elements in hash table.i want to add the values of this variables in hash table each time as the values change.
To mutate an object, you have to call its properties. An object property is either a field or a method. In your case put is a method of the hashT object. A method call is done by writing the object name, then the dot operator, then the method name and finally the arguments surrounded by parenthesis:
objectName.methodName(argument1, argument2, ...);
The problem is here:
hashT.put<sum2 , g>;
put is a method and to call it you have to surround the arguments (sum2 and g) with parenthesis:
hashT.put(sum2, g);
You need to follow the comments and edit your title so its a meaningful title that will help other people understand what your question is about.
Also, when you get an error, copy the big red text that is displayed in the console (color depends on which editor you are using), also known as the error's "Stack Trace" and past it into your question somewhere. This will help us pinpoint what is going on, and the error title itself will likely give away to us exactly what's wrong.
However, without any context on what the error is and what is before or after those two lines of code it is difficult to determine if you have previously defined sum2 or g as a variable that stores values. I am going to assume you haven't assigned at least one of them, likely g as a variable.
For experimental purposes, try replacing those two lines of code with:
Hashtable <Integer,String> hashT=new Hashtable<Integer ,String >();
hashT.put<0 , "g">;
That is putting zero (0) as an explicit integer and g as an explicit string into the hashtable. If you need to put variables into there, then you need to define them before hand, like this:
int sum2 = 3 + 4;
String g = "Some String";
Hashtable <Integer,String> hashT=new Hashtable<Integer ,String >();
hashT.put<sum2 , g>;
Now the integer value 7 is stored as the hash and the string Some String as the mapped value.
When debugging a java program in Eclipse, I can see (e.g. in the Variables view) the content of an arbitrary array, see the picture bellow (with the ByteArrayInputStream.buf field).
But I cannot find the array length field anywhere. Is there a way to show the length of an array in Eclipse debugger? How can I do it?
You can use the "Expressions" view and evaluate the length member:
Keep in mind that the last index is one less than the length!
While this works for public array members, it seems that an explicit cast is required for protected members. Consider the following code:
...
ByteArrayInputStream is = new ByteArrayInputStream(new byte[1769]);
...
Now, when evaluating is.buf, the Expressions view shows a dump of the array as shown in the question, but evaluating is.buf.length fails with <error(s)_during_the_evaluation>. If we add an explicit cast to ByteArrayInputStream, the evaluation works:
Thank you #ThorbjørnRavnAndersen for your answer (comment). You are right, the latest array segment (in my case: [1700..1768]) holds the length.
The whole picture:
In a Java class in my XPages application, I'm trying to get a handle on a Notes Document in a Notes View. The Notes View contains several Notes Documents. To get the Notes Document I want, I use 2 keys. This produces an error. If I use just one key, the first Notes Document in the Notes View is returned. The Notes View contains two sorted columns. The first column contains the empLang value, the second column contains the templateType value. Here is my code:
String empLang = "en";
String templateType = "C";
Database dbCurr = session.getCurrentDatabase();
String viewName = "vieAdminTemplates" + empLang;
View tview = dbCurr.getView(viewName);
Vector viewKey = new Vector();
viewKey.addElement(empLang);
viewKey.addElement(templateType); // this line causes the code to fail
Document templateDoc = tview.getDocumentByKey(viewKey);
What could be the cause of this problem?
A couple of ideas
1) You could concatenate the key into a single column since you said that worked. Something like 'en~C'
2) You could use the database.search method where you include a string of formula language that isolates the document you want. It returns a collection, and then you pull the document from there.
getDocumentByKey works with multiple columns. There's a known problem with doubles, but you're not hitting that there. One thing that stands out is the second column is just a single letter. That could be considered as a Char instead of a String, either when you do addElement or by the view.
I'd recommend debugging out what data type they are. viewKey.get(1).getClass().getName() I think gives you the class it's stored as. Doing the same for the View Column value.
When you say it causes the code to fail, how does it fail? Does it just not return anything or throw an error?
My next step would be to try testing it where the View and the Vector contain more than one character, e.g. "CC", to help check if there's an underlying issue with Java getDocumentByKey and single characters.
I'm very sorry. The problem here is that the view name in the code is incorrect. There is a view "vieAdminTemplates" but it does not have a second column containing the value "C". With the correct view, the code works fine. Thanks for taking the time to respond to my question.
I am currently trying to perform some regex on the result of a DatagramPacket.getData() call.
Implemented as String myString = new String(thepkt.getData()):
But weirdly, java is dropping the end quotation that it uses to encapsulate all data(see linked image below).
When I click the field in the variable inspector during a debug session and don't change anything, when I click off the variable field it corrects itself again without me changing anything. It even highlights the variable inspection field in yellow to signal change.
Its values are also displaying like it is still a byte array rather than a String object
http://i.imgur.com/8ZItsZI.png
It's throwing off my regex and I can't see anything that would cause it. It's a client server simulation and on the client side, the getData returns the data no problem.
I got it working by using the solution provided in:
https://stackoverflow.com/a/8557165/1700855
But I still don't understand how not specifying the length of the packet to the String constructor would cause it to drop the systematic end double quotes. Can anyone provide an explanation as I really like to understand solutions to my issues before moving on :)
The problem is that you didn't read the spec for DatagramPacket.getData:
Returns the data buffer. The data received or the data to be sent
starts from the offset in the buffer, and runs for length long.
So, to be correct, you should use
new String(thepkt.getData(), thepkt.getOffset(), thepht.getLength())
Or, to not use the default charset:
new String(thepkt.getData(), thepkt.getOffset(), thepht.getLength(), someCharset)