How to rename a String variable dynamically using javassist? - reflection

I have a class named Sample and I need to rename the variable messageID to NameID, such that the corresponding getter and setter are also updated.
public class Sample{
String messageID;
public String getMessageID() {
return MessageID;
}
public void setMessageID(String messageID) {
MessageID = messageID;
}
}

With Javassist you can change the field name and all the references from old field name to the new one.
ClassPool classpool = ClassPool.getDefault();
CtClass ctClass = classpool.get(Sample.class.getName());
CtField field = ctClass.getField("messageID");
CodeConverter codeConverter = new CodeConverter();
codeConverter.redirectFieldAccess(field, ctClass, "NameID");
ctClass.instrument(codeConverter);
field.setName("NameID");
If you don't know ho to use Javassist you should read this tutorial here
The trick about "rewiring" all field references is done using a CodeConverter that will replace all references to the CtField field for the references to the field named NameID in ctClass. Keep in mind that this needs to be done before renaming the field into NameID.
However you should remember that all the references are updated but the set/get methods names are still getMessageID and setMessageID. You can easily change that using the same reference of ctClass as follow:
CtMethod getter = ctClass.getDeclaredMethod("getMessageID");
getter.setName("getNameId");
CtMethod setter = ctClass.getDeclaredMethod("setMessageID");
setter.setName("setNameId");

Related

DynamicJasper and OneToMany

I have a two classes that are in OneToMany relationship:
Lager and supplier.
so when i have list of objects, i have also object and with standard java i can access fields of object.
when i do this
AbstractColumn columnName = ColumnBuilder.getNew()
.setColumnProperty("name", String.class.getName())
.setTitle("Name").setWidth(85)
.build();
i get a good result, but when i do
AbstractColumn sellerColumn = ColumnBuilder.getNew()
.setColumnProperty("seller" ,Seller.class.getName() )
.setTitle("seller").setWidth(85).build();
i just get toString method of my seller object, so my question is how to access field of seller when i am creating my DynamicJasper column
so i added now a picture to better
#OneToMany(mappedBy ="seller", cascade = CascadeType.REMOVE,fetch=FetchType.LAZY)
public List<Lager> getLager() {
return lager;
}
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "seller_id")
public Seller getSeller() {
return seller.get();
}
this are the relations between these two objects, how could i just show name of my seller object, and not the entire toString method.
Well at the end i found a way, i changed following method :
AbstractColumn sellerColumn = ColumnBuilder.getNew()
.setColumnProperty("seller" ,Seller.class.getName() )
.setTitle("seller").setWidth(85).build();
to
AbstractColumn sellerColumn = ColumnBuilder.getNew()
.setColumnProperty("seller.seller_name" ,Seller.class.getName() )
.setTitle("seller").setWidth(85).build();
after that everything worked, the thing is , i did try this, but for some reason my page did not load properly, when i did clean and build it worked flawlessly.
just to note that seller.seller_name is :
seller = my pojo class
and
seller_name
= my field that has getters and setters.

Using Objects in a dictionary in vb.net

This is how I Check if my dictionary occurences already contains a key and a value and assign keys and values to it... but I need another value, so how do I use the object here?
Occurences.Add(xRows.Cells(4).Value.ToString(), Object)
Somehow like this:
occurences(xRows.Cells(4).Value.ToString()) = Double.Parse(occurences(xRows.Cells(4).Value.ToString()).ToString()) + <"1st object value here">)
But this is how I currently do it which only has a key and a value but I need something like key, object which has (value, value), something like that:
Actual code:
If (occurences.ContainsKey(xRows.Cells(4).Value.ToString())) Then
occurences(xRows.Cells(4).Value.ToString()) = Double.Parse(occurences(xRows.Cells(4).Value.ToString()).ToString()) + Double.Parse(xRows.Cells(7).Value.ToString())
Else
occurences.Add(xRows.Cells(4).Value.ToString(), Double.Parse(xRows.Cells(7).Value.ToString()))
End If
Next
Then i have another code for insert where i need to use the 2nd value of the object.
Using commm As New MySqlCommand()
With commm
.Parameters.Clear()
.Parameters.AddWithValue("#iBrnchCde", cmbBrnchCode.Text)
.Parameters.AddWithValue("#iFCode", pair.Key)
.Parameters.AddWithValue("#iDesc", <"2nd OBJECT VALUE HERE"> )
.Parameters.AddWithValue("#iQty", pair.Value)
.CommandText = oInsertString
.Connection = _conn
.CommandType = CommandType.Text
End With
commm.ExecuteNonQuery()
End Using
Do the following:
Class CustomRowObject
Public Property Name() As String
Public Property Quantity() As Double
Public Property Description() As String
End Class
If (occurences.ContainsKey(xRows.Cells(4).Value.ToString())) Then
occurences(xRows.Cells(4).Value.ToString()).Quantity = Double.Parse(occurences(xRows.Cells(4).Value.ToString()).ToString()) + Double.Parse(xRows.Cells(7).Value.ToString())
Else
occurences.Add(xRows.Cells(4).Value.ToString(),New CustomRowObject With { .Name = a.Cells("ProductName").Value.ToString(),.Description = .Cells("ProductDesc").Value.ToString(), .Quantity = a.Cells("Quantity").Value.ToString()})
End If
Next
Then reference it via occurences("keynamegoeshere").Quantity for use in your SQL.
I'm not sure I understand your question fully, but if I do I would suggest a different approach:
Why not make a class that holds your values, then add your class to the dictionary - or - create a dictionary of the class type:
Public myClass
Public Code As String
Public Desc as String
....
End Class
Dim myClassInstance as New myClass
'initialize fields
occurences.Add(key, myClassInstance)
To retrieve get the value as an object and use if typeof value is myclass then - if you choose object as type for the dictionary.
If you choose object you can store different classes and types of course, but the cost is the casting. If possible make a dictionary of the type you will use to avoid casting.
Private myDictionary as New Dictionary(Of String, myClass)

ClearCanvas DicomFile.DataSet -- How to add a new Tag?

im trying to add a new tag to my DicomFile.DataSet in ClearCanvas.
I notice there is the method "DicomFile.DataSet.RemoveAttribute" but no "AddAtribute" method. So I have been looking at the method "LoadDicomFields" & "SaveDicomFields" but so far can't seem to get them to work. Ive tried to pass in a "DicomFieldAttribute" to these methods, but to no avail.
What am I missing here? Or what do I need to do to add a new tag to the DataSet.
DicomFieldAttribute c = new DicomFieldAttribute(tag);
List<DicomFieldAttribute> cs = new List<DicomFieldAttribute>();
cs.Add(c);
DicomFile.DataSet.LoadDicomFields(cs);
DicomFile.DataSet.SaveDicomFields(cs);
if(DicomFile.DataSet.Contains(tag))
{
tag = 0; //BreakPoint never reached here
}
Or I tried this as well::
DicomFieldAttribute c = new DicomFieldAttribute(tag);
DicomFile.DataSet.LoadDicomFields(c);
DicomFile.DataSet.SaveDicomFields(c);
if(DicomFile.DataSet.Contains(tag))
{
tag = 0; //BreakPoint never reached here
}
Ive been stuck on what would seem to be a trivial task.
You're confusing a bit the use of attributes. The DicomFiledAttribute is a .NET attribute that can be placed on members of a class so that the class is automatically populated with values from a DicomAttributeCollection or or to have the class automatically populated with values from the DicomAttribute Collection. Ie, given a test class like this:
public class TestClass
{
[DicomField(DicomTags.SopClassUid, DefaultValue = DicomFieldDefault.Default)]
public DicomUid SopClassUid = null;
[DicomField(DicomTags.SopInstanceUid, DefaultValue = DicomFieldDefault.Default)]
public DicomUid SOPInstanceUID = null;
[DicomField(DicomTags.StudyDate, DefaultValue = DicomFieldDefault.Default)]
public DateTime StudyDate;
}
You could populate an instance of the class like this:
DicomFile file = new DicomFile("filename.dcm");
file.Load();
TestClass testInstance = new TestClass();
file.DataSet.LoadDicomFields(testInstance);
// testInstance should now be populated with the values from file
If you're interested in just populating some DICOM tags, the DicomAttributeCollection has an indexer in it. The indexer will automatically create a DicomAttribute instance if it doesn't already exist, for the tag requested via the indexer. So, to populate a value, you can do soemthing like this:
DicomFile file = new DicomFile("filename.dcm");
file.DataSet[DicomTags.SopInstanceUid].SetStringValue("1.1.1");
If you want to create the DicomAttribute yourself, you can do something like this:
DicomAttribute attrib = new DicomAttributeUI(DicomTags.SopInstanceUid);
attrib.SetStringValue("1.1.1");
DicomFile file = new DicomFile("filename.dcm");
file.DataSet[DicomTags.SopInstanceUid] = attrib;

in asp.net dynamic date, how to use partial method to validate fields aganist data in database

i want to make sure all product names are unique so i tried to do the following.
but it is causing an infinity loop at the lambda expression.
public partial class Product
{
partial void OnProductNameChanging(string value)
{
using(var ctx = new MyEntityContext()){
var val = value;
var item = ctx.Products.Where(o=>o.ProductName == val).FirstOrDefault();
if(item != null)
throw new ValidationException("Product Name existed.");
}
}
}
i'm using asp.net 4.0 with dynamic data and entity framework.
Why don't you set it up on database level and handle exeption in case if product name already exists?
I am not too familiar with EF, but you should get the changeset and compare values. That is, for the Product Entity and in the case of the the changeset having an Update, compare the EXISTING value with NEW, and change the new in the case of duplication.
Here's how to get changeSet in EF :
http://davidhayden.com/blog/dave/archive/2005/11/16/2570.aspx
the comparison and value must be called before any context.SubmitChanges();
Hope this helps.

Change Single URL query string value

I have an ASP.NET page which takes a number of parameters in the query string:
search.aspx?q=123&source=WebSearch
This would display the first page of search results. Now within the rendering of that page, I want to display a set of links that allow the user to jump to different pages within the search results. I can do this simply by append &page=1 or &page=2 etc.
Where it gets complicated is that I want to preserve the input query string from the original page for every parameter except the one that I'm trying to change. There may be other parameters in the url used by other components and the value I'm trying to replace may or may not already be defined:
search.aspx?q=123&source=WebSearch&page=1&Theme=Blue
In this case to generate a link to the next page of results, I want to change page=1 to page=2 while leaving the rest of the query string unchanged.
Is there a builtin way to do this, or do I need to do all of the string parsing/recombining manually?
You can't modify the QueryString directly as it is readonly. You will need to get the values, modify them, then put them back together. Try this:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
nameValues.Set("page", "2");
string url = Request.Url.AbsolutePath;
string updatedQueryString = "?" + nameValues.ToString();
Response.Redirect(url + updatedQueryString);
The ParseQueryString method returns a NameValueCollection (actually it really returns a HttpValueCollection which encodes the results, as I mention in an answer to another question). You can then use the Set method to update a value. You can also use the Add method to add a new one, or Remove to remove a value. Finally, calling ToString() on the name NameValueCollection returns the name value pairs in a name1=value1&name2=value2 querystring ready format. Once you have that append it to the URL and redirect.
Alternately, you can add a new key, or modify an existing one, using the indexer:
nameValues["temp"] = "hello!"; // add "temp" if it didn't exist
nameValues["temp"] = "hello, world!"; // overwrite "temp"
nameValues.Remove("temp"); // can't remove via indexer
You may need to add a using System.Collections.Specialized; to make use of the NameValueCollection class.
You can do this without all the overhead of redirection (which is not inconsiderable). My personal preference is to work with a NameValueCollection which a querystring really is, but using reflection:
// reflect to readonly property
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isReadOnly.SetValue(this.Request.QueryString, false, null);
// remove
this.Request.QueryString.Remove("foo");
// modify
this.Request.QueryString.Set("bar", "123");
// make collection readonly again
isReadOnly.SetValue(this.Request.QueryString, true, null);
Using this QueryStringBuilder helper class, you can grab the current QueryString and call the Add method to change an existing key/value pair...
//before: "?id=123&page=1&sessionId=ABC"
string newQueryString = QueryString.Current.Add("page", "2");
//after: "?id=123&page=2&sessionId=ABC"
Use the URIBuilder Specifically the link textQuery property
I believe that does what you need.
This is pretty arbitrary, in .NET Core at least. And it all boils down to asp-all-route-data
Consider the following trivial example (taken from the "paginator" view model I use in virtually every project):
public class SomeViewModel
{
public Dictionary<string, string> NextPageLink(IQueryCollection query)
{
/*
* NOTE: how you derive the "2" is fully up to you
*/
return ParseQueryCollection(query, "page", "2");
}
Dictionary<string, string> ParseQueryCollection(IQueryCollection query, string replacementKey, string replacementValue)
{
var dict = new Dictionary<string, string>()
{
{ replacementKey, replacementValue }
};
foreach (var q in query)
{
if (!string.Equals(q.Key, replacementKey, StringComparison.OrdinalIgnoreCase))
{
dict.Add(q.Key, q.Value);
}
}
return dict;
}
}
Then to use in your view, simply pass the method the current request query collection from Context.Request:
<a asp-all-route-data="#Model.NextPageLink(Context.Request.Query)">Next</a>

Resources