Acessing fields within rule - ANtlr4 - field

I have a rule where I have a declaration returns
tablename
returns [String fieldString, TableObj obj]
TableObj is a custom class that I declare in the same g4 file
class TableObj {
public String realName;
public String aliasName;
public List<String> fields;
public List<Relation> relations;
public TableObj(){
fields = new ArrayList<String>();
relations = new ArrayList<Relation>();
}
}
but when I have to try access a field of obj using $obj.field the generated code is:
_localCtx.field
instead of
_localCtx.obj.field
How do I do to obtain the second form instead of the first?
If it will need or it will help follows a snippet of my rule
tablename
returns [String fieldString, TableObj obj]
:
(tablePrefix=ID {
$obj.aliasName = $tablePrefix.text;
System.out.println( "Alias = " + $tablePrefix.text + " " + $obj.aliasName );
}
;

This is a bug in ANTLR that you should report to the project issue tracker:
https://github.com/antlr/antlr4/issues

Related

spring data neo4j 6 #Query passing list param throws ConverterNotFoundException on converting from List<Pojo> to type [org.neo4j.driver.Value]

I tried to update relationship properties using custom query with #Query where its working with java object but not with collection<T> / List<T> as seen below:
#Query("UNWIND $relations \n" +
"AS item \n" +
"MATCH (f:PERSON {nid: $from})-[r:KNOWS]->(t:LANGUAGE {name: $to}) \n" +
"WHERE ID(r) = item.id SET r.description = item.description \n" +
"return f, collect(r), collect(t)")
ResponseType updateRelation(#Param("from") String from, #Param("to") String to, #Param("relations") List<KnowsEntity> relEntites);
when i invoke this method it throws error as follows:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [*.KnowsEntity] to type [org.neo4j.driver.Value]
Does this mean i need an custom converter to make this work?
also, when i hard-coded the json structure as below like we do in neo4j browser, it works fine.
Note: with subject to the keys should not be in quotes!
#Query("UNWIND [{description:\"defining value\",id:0},{description:\"blah blah\",id:3}] \n" +
"AS item \n" +
"MATCH (f:PERSON {nid: $from})-[r:KNOWS]->(t:LANGUAGE {name: $to}) \n" +
"WHERE ID(r) = item.id SET r.description = item.description \n" +
"return f, collect(r), collect(t)")
ResponseType updateRelation(#Param("from") String from, #Param("to") String to);
Please correct me whether am i missing something / any better way to get this updated using list of objects.
Thanks for asking this, I think this is just a missing feature: https://github.com/spring-projects/spring-data-neo4j/issues/2292
The fix link is working in locally build inputs. Thanks #Michael Simons
But, if the input is via http payload, then we need Entity level change for #RequestBody to get serialized and pass through the SDN.
#RelationshipProperties
#Data
public class KnowsEntity {
#JsonView(Views.Public.class) // it might not be needed
#Id
#GeneratedValue
private Long id;
#JsonView(Views.Public.class)
#Property
private Boolean read;
#JsonView(Views.Public.class)
#Property
private Boolean write;
#JsonView(Views.Public.class)
#TargetNode
private Language language;
}
#Node(primaryLabel = "LANGUAGE")
public class Language {
#JsonView(Views.Public.class)
#Id
private String name;
}
public class Views {
public static class Public {
}
}
and in controller get param as
#RequestBody #JsonView(Views.Public.class) Set<KnowsEntity> knows

MVC - validation attributes with error messages from database

I need to keep my translations in database so users can add, delete, and change them. I hold all of my translations in a table with composite primary key (variableName, culture), where variableName is just a name of some text which can have multiple translations and they correspond to the culture which is a string, like "en-US". So for example I have a variable "submitLogin" which I display on login button and there are three languages in my database: English, German, and Polish. This means I keep three rows in my table for that particular text: ("submitLogin", "en-US", "English translation), ("submitLogin", "de-DE", "German translation") and ("submitLogin", "pl-PL", "Polish translation").
So far my application has been based on a class Resources.cs which contains all translation variables from database, e.g.:
public static string buttonContinueShopping {
get {
return (string) resourceProvider.GetResource("buttonContinueShopping", CultureInfo.CurrentUICulture.Name);
}
}
In views I use these static properties to get my translations like this:
#Resources.buttonContinueShopping
I can create a dynamic type which will behave exactly the same way in views (except not having static properties but I can create an object on every view, that's not the problem - although it doesn't seem nice):
public class Resource : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
ResourceManager rsManager = new ResourceManager();
result = rsManager.GetString(binder.Name);
return true;
}
}
But I have a problem with my models' attributes. So far I've used them like this:
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "errorRequired")]
[DataType(DataType.EmailAddress, ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "errorWrongDataType")]
[EmailAddress]
[Display(Name = "nameEmail", ResourceType = typeof(Resources.Resources))]
public string Email { get; set; }
Now I have to get rid of my Resources.cs because they are generated after running a console program which reads all unique values of translation variables from database and creates properties (like the one I showed above). I cannot have this file anymore because users can add new translation variables in runtime.
How do I change as little as possible and make these attributes read error messages, display names etc. from database?
I have three ideas but I don't know how to get them done:
Use custom attributes - I tried it for Required attribute but it just doesn't add any client-side validation nor any error messages in HTML.
Use custom DataAnnotationsModelMetadataProvider - I tried this but it doesn't work after reloading the page - on the first page load all errors exist (particularly this: 'Field Email is required.') but after reloading the page, required error message changes to 'Field is required'. This is what I do:
public class CustomDataAnnotationsProvider: DataAnnotationsModelMetadataProvider
{
private ResourceManager resourceManager = new ResourceManager();
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
string key = string.Empty;
string localizedValue = string.Empty;
foreach (var attr in attributes)
{
if (attr != null)
{
if (attr is DisplayAttribute)
{
key = ((DisplayAttribute)attr).Name;
if (!string.IsNullOrEmpty(key) && !key.Contains(" "))
{
localizedValue = resourceManager.GetString(key);
((DisplayAttribute)attr).Name = localizedValue;
}
}
else if (attr is ValidationAttribute || attr is RequiredAttribute)
{
key = ((ValidationAttribute)attr).ErrorMessage;
if (!string.IsNullOrEmpty(key) && !key.Contains(" "))
{
localizedValue = resourceManager.GetString(key);
((ValidationAttribute)attr).ErrorMessage = localizedValue;
}
}
}
}
return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
}
Global.asax:
ModelMetadataProviders.Current = new CustomDataAnnotationsProvider();
Model:
[Required(ErrorMessage = "errorRequired")]
[EmailAddress(ErrorMessage = "errorWrongDataType")]
[Display(Name = "nameEmail")]
public string Email { get; set; }
Use reflection (would be the best but I have no idea how to do it). Let's say I leave my attributes like that and remove all properties from my Resources.cs. Now what does RequiredAttribute do? It takes the type given and gets the property given, so e.g. It tries to do this:
Resources.Resources.nameEmail.get
The question is: is it possible to write some reflection code which would take care of 'requests' for non-existing properties (like nameEmail)?
I think the answer is to supply a default value in your Resources.cs file. Whilst users can supply translations dynamically, your application cannot use them unless they have the key, which you have used in the model.
If you modify your existing method to accept a default value then you can return this if there is not a database value present:
public static string buttonContinueShopping {
get {
return GetResource("buttonContinueShopping",
CultureInfo.CurrentUICulture.Name, "Continue Shopping");
}
}
public string GetResource(string key, string cultureName, string defaultText)
{
// Get db value
if (dbValue != null)
return dbValue;
return defaultText;
}
You control the keys by manually modifying them in Resources.cs which IMO is the best place for them, as they are maintained in the same project as they are being used. You can (and I have used this technique) then write a companion console app that can use reflection to generate the sql needed to update the database.
This example is taken directly from my project but you can get the idea
static void Main(string[] args)
{
var resources = typeof(Resources).GetProperties();
StreamWriter streamWriter = new StreamWriter(new FileStream(#"..\..\Resources.sql", FileMode.Create));
streamWriter.WriteLine(createTable);
for (int i = 0; i < resources.Count(); i++)
{
var line = GetValues(resources[i].Name, resources[i].GetValue(null, null) as string);
if (i == 0)
{
streamWriter.Write(insertValues + line);
}
else if (i == resources.Count() - 1)
{
streamWriter.Write(",\r\n" + line + "\r\nGO");
}
else if (i % 4 == 0)
{
streamWriter.Write("\r\nGO\r\n\r\n" + insertValues + line);
}
else
{
streamWriter.Write(",\r\n" + line);
}
}
streamWriter.Flush();
streamWriter.Close();
}
private static string createTable = "IF NOT EXISTS (SELECT * FROM sys.objects where Object_Id = OBJECT_ID(tempdb..#Resources))"
+ "\r\n\tCREATE TABLE Resources (StaticTextKey VARCHAR(100), DefaultText VARCHAR(MAX))\r\nGO\r\n";
private static string insertValues = "INSERT INTO #Resources (StaticTextKey, DefaultText) VALUES\r\n";
private static string GetValues(string staticTextKey, string defaultText)
{
return string.Format("('{0}', '{1}')", staticTextKey, defaultText.Replace("'", "''"));
}

LINQ - Dynamic expression to OrderBy

I have a little issue, I'll try to explain this in detail.
Over my system I have a Generic Repository working with EF 4.1.
Everything works fantastic, but I have a problem in a certain situation I would need to do dynamic orderBy over some querys.
I recieve by parameter an "string" that represent the field on my class, to do the orderBy (like "id" or "description")
Some portion of code:
public class SomeClass
{
public int id { get; set; }
public string description { get; set; }
}
// First we define the parameter that we are going to use
// in our OrderBy clause. This is the same as "(parameter =>"
// in the example above.
var param = Expression.Parameter(typeof(SomeClass), "parameter");
// Now we'll make our lambda function that returns the
// request.SortingName property by it's name.
var expression = Expression.Lambda<Func<SomeClass, int>>(Expression.Property(param, request.SortingName), param);
Well, this code works if the "request.SortingName" is type "int" (id) , but if I want to make the orderBy by "string" (description) or another type this code doesn't work.
I changed the expression to using "object":
var expression = Expression.Lambda<Func<SomeClass, object>>(Expression.Property(param, request.SortingName), param);
But when I run the code, the compiler throws the next exception:
Expression of type 'System.Int32' cannot be used for return type 'System.Object'
In case the property is string type, the exception is
Expression of type 'System.String' cannot be used for return type 'System.Object'
In other words the code doesn't work with "object" type.
Anyone knows how can I figure this out?
Thanks for your time.
Here's how I do dynamic sort and paginate using EF4 and some generic methods I've created in my standard dev library. The important thing is the second bit of code which you use to create the Lambda expression for the SortBy method.
public enum SqlOrderByDirecton
{
ASC,
DESC
}
//Derive Lambda Expression from string
string sortByKey = "BusinessId";
string value = "DESC";
var p = Expression.Parameter(typeof(T));
this.SortBy = Expression.Lambda<Func<T, dynamic>>(Expression.TypeAs(Expression.Property(p, sortByKey), typeof(object)), p).Compile();
this.SortOrder = (DevCore.SqlOrderByDirecton)Enum.Parse(typeof(DevCore.SqlOrderByDirecton), value, true);
public static List<T> SortAndPaginate<T>(IEnumerable<T> query,
Func<T, object> sortBy,
SqlOrderByDirecton sortOrder,
int rowLimit,
int startRecord,
out int recordCount)
{
recordCount = query.Count();
List<T> list = new List<T>();
if (sortOrder == SqlOrderByDirecton.ASC)
{
list = query.OrderBy(sortBy).Skip(startRecord).Take(rowLimit).ToList();
}
else
{
list = query.OrderByDescending(sortBy).Skip(startRecord).Take(rowLimit).ToList();
}
return list;
}

MVC 3 Reusable Remote Validation with DB Lookup

I have an MVC 3 appliation which I have many integer fields on a form. They all require range validation but the ranges exists in a table in my database. So I would like to create a reusable remote validation tool which will look up the min and max value and return the validation to the view.
I am updating this with some example code of what I would like to do to see my request might clarify what I am looking for:
In my validation class:
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW1_Web_Tension_SP { get; set; }
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW2_Web_Tension_SP { get; set; }
[Remote("CheckIntegerRange", "Validation", ErrorMessage = "Value outside of range")]
public object UW3_Web_Tension_SP { get; set; }
In my ValidationController I tried to create a function with multiple parameters but I dont think I can - however I think it shows what I am trying to do more clearly:
public class ValidationController : Controller
{
public JsonResult CheckIntegerRange(int integer, string EntityName, string AttributeName)
{
var result = false;
int MinInteger = 0;
int MaxInteger = 100;
//declare recipe entities
var context = new MadicoRecipeEntities();
//set sql statements and get description, etc from attributes view
var esqlIntegerAttributeDetails = "SELECT VALUE c FROM MadicoRecipeEntities.v_AttributeIntegerRangeDetails AS c " +
"WHERE c.EntityName = '" + EntityName + "' AND c.Attribute = '" + AttributeName + "'";
var queryAttributeDetails = context.CreateQuery<v_AttributeIntegerRangeDetails>(esqlIntegerAttributeDetails);
var RecipeAttributes = queryAttributeDetails.ToList();
foreach (var AttributeDetails in RecipeAttributes)
{
MinInteger = AttributeDetails.Min;
MaxInteger = AttributeDetails.Max;
}
return Json(result, JsonRequestBehavior.AllowGet);
}
}
I have found the following post on the asp.net forums which handled my first obstacle - passing different named attributes to the same validator. However, in this example the name is passed in generically - I need to have the name in order to query the table to get the applicable min and max ranges.
http://forums.asp.net/t/1625928.aspx/3/10
Can anyone point me in the right direction?
Thanks!
It is called remote validation! Here is an example:
remote validation

ASP.NET MVC Passing Lists to RouteData QueryString

The recommended approach for passing lists of values as a QueryString is
www.site.com/search?value=1&value=2&value=3&value=4
ASP.NET handles this well:
string value = QueryString.Get("value"); // returns "1,2,3,4"
But I can't figure out a way of passing these values by into RouteData. The obvious approach would be to add
int[] value = {1,2,3,4};
into the RouteData and have super smart MVC sort things out for me. Unfortunately MVC is dump when it comes to passing arrays into RouteData, it basically calls .ToString() adding value=int[] to my QueryString.
I tried adding the values to RouteValueDictionary (but being a dictionary can't handle this:)
RouteValueDictionary dict = new RouteValueDictionary();
dict.Add("value","1");
dict.Add("value","2"); // Throws Exception (Keys must be unique)
I could try passing values like this:
www.site.com/search?value=1,2,3,4
but this is Encoded to the URL as
www.site.com/search?value=1%2C2%2C3%2C4
I'm not sure if this is a bad thing or not,but it sure looks bad.
So, how do you pass lists of values as RouteData in ASP.NET MVC. Is there any way I can add to MVC to make it handle an int[]? Or is the underlying Dictionary-based data structure a show-stopper for passing lists of values easily to ASP.NET MVC?
I've come up with a solution to this myself by making a new class RouteDataList()
public class RouteDataList<T> : List<T>
{
public RouteDataList(IEnumerable<T> enumerable) : base(enumerable) { }
public RouteDataList() : base() { }
public override string ToString()
{
string output = "";
for (int i = 0; i < this.Count; i++)
{
output += i < this.Count - 1 ? this[i] + "-" : this[i].ToString();
}
return output;
}
public static List<Int32> ParseInts(string input)
{
if (String.IsNullOrEmpty(input)) return null;
List<Int32> parsedList = new List<int>();
string[] split = input.Split('-');
foreach (string s in split)
{
int value;
if(Int32.TryParse(s, out value)) parsedList.Add(value);
}
return parsedList;
}
}
Use as follows:
RouteDataList<Int32> valuelist = new RouteDataList<Int32>(){5,6,7,8};
RouteDataList<Int32> anothervaluelist = new RouteDataList<Int32>(){12,13,14,15};
Then Pass to any function that takes a RouteValueDictionary/Anonymous Type:
return RedirectToAction("View", "Browse", new {valuelist, anothervaluelist } );
// Produces http://www.site.com/browse/view?valuelist=5-6-7-8&anothervaluelist=12-13-14-15
// To Parse back to a list:
List<Int32> values = RouteDataList<Int32>.ParseInts(HttpContext.Current.Request.QueryString["valuelist"])

Resources