How to handle field with multiple possible types - jsonschema2pojo

Is there a better way to handle a field whose value could be different types in jsonschema2pojo rather than having that field generated as java.lang.Object (this is all caused by legacy data that can't be migrated)
For instance, if I have these JSON:
"foo" is String
{
"foo": "bar"
}
"foo" is Array
{
"foo": ["bar", "baz"]
}
I've tried declaring "type" as either a "string" or "array" in hopes the deserialization would somehow be smart enough to transform the value or force cast to either one (didn't work):
{
"type":"object",
"properties": {
"foo": {
"type": "string"
}
}
}
{
"type":"object",
"properties": {
"foo": {
"type": "array"
}
}
}
{
"type": "object",
"properties": {
"foo": {
"existingJavaType": "java.util.List<String>"
}
}
}
How would you recommend I handle this situation? Do I have no choice but to declare "foo" as an Object.
{
"type":"object",
"properties": {
"foo": {
}
}
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"foo"
})
#Generated("jsonschema2pojo")
public class Example {
#JsonProperty("foo")
public Object foo;
}
I know I could define a second class that handle the logic for casting Object but I'd like to avoid that if possible. Such as:
public class Test extends Example {
#Override
public List<String> getFoo(){
// if this.foo instanceof string return List<String>
// else return this.foo
}
}

You should use Object type and use instanceOf keyword for checking the datatype of the object, once known the type you can use it accordingly. Check the example below:
public void set(final String key, final Object value) {
final SharedPreferences.Editor editor = sPreferences.edit();
if (value instanceof String) {
editor.putString(key, (String) value);
editor.commit();
} else if (value instanceof Float) {
final Float objFloat = (Float) value;
editor.putFloat(key, objFloat.floatValue());
editor.commit();
} else if (value instanceof Long) {
final Long objFloat = (Long) value;
editor.putLong(key, objFloat.longValue());
editor.commit();
} else if (value instanceof Integer) {
final Integer objFloat = (Integer) value;
editor.putInt(key, objFloat.intValue());
editor.commit();
} else if (value instanceof Boolean) {
final Boolean objFloat = (Boolean) value;
editor.putBoolean(key, objFloat.booleanValue());
editor.commit();
}else if (value instanceof Double) {
editor.putLong(key, Double.doubleToRawLongBits((Double)value));
editor.commit();
}
}

Related

why scala in this case can't use single abstract method?

i use spring boot's RedisTemplate with scala, and i write this code:
redisTemplate1.executePipelined(new RedisCallback[String] {
override def doInRedis(connection: RedisConnection): String = {
MyCode......
null
}
}, redisTemplate1.getValueSerializer)
usually, it's can be wrote like this:
redisTemplate1.executePipelined((connection: RedisConnection) => {
MyCode......
null
}, redisTemplate1.getValueSerializer)
and this style is running well in java:
redisTemplate1.executePipelined((RedisConnection conn) -> {
MyCode......
return null;
}, redisTemplate1.getValueSerializer());
but when i compile in this style with scala, i get an error, so why this happend and how can i use single abstract method in this case?
overloaded method value executePipelined with alternatives:
(x$1: org.springframework.data.redis.core.RedisCallback[_],x$2: org.springframework.data.redis.serializer.RedisSerializer[_])java.util.List[Object] <and>
(x$1: org.springframework.data.redis.core.SessionCallback[_],x$2: org.springframework.data.redis.serializer.RedisSerializer[_])java.util.List[Object]
cannot be applied to (org.springframework.data.redis.connection.RedisConnection => Null, org.springframework.data.redis.serializer.RedisSerializer[?0(in method syncSegmentSrc)])
redisTemplate1.executePipelined((connection: RedisConnection) => {
the executePipelined function source code like this:
#Override
public List<Object> executePipelined(SessionCallback<?> session, #Nullable RedisSerializer<?> resultSerializer) {
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(session, "Callback object must not be null");
RedisConnectionFactory factory = getRequiredConnectionFactory();
// bind connection
RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
try {
return execute((RedisCallback<List<Object>>) connection -> {
connection.openPipeline();
boolean pipelinedClosed = false;
try {
Object result = executeSession(session);
if (result != null) {
throw new InvalidDataAccessApiUsageException(
"Callback cannot return a non-null value as it gets overwritten by the pipeline");
}
List<Object> closePipeline = connection.closePipeline();
pipelinedClosed = true;
return deserializeMixedResults(closePipeline, resultSerializer, hashKeySerializer, hashValueSerializer);
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}
}
});
} finally {
RedisConnectionUtils.unbindConnection(factory);
}
}
#Override
public List<Object> executePipelined(RedisCallback<?> action, #Nullable RedisSerializer<?> resultSerializer) {
return execute((RedisCallback<List<Object>>) connection -> {
connection.openPipeline();
boolean pipelinedClosed = false;
try {
Object result = action.doInRedis(connection);
if (result != null) {
throw new InvalidDataAccessApiUsageException(
"Callback cannot return a non-null value as it gets overwritten by the pipeline");
}
List<Object> closePipeline = connection.closePipeline();
pipelinedClosed = true;
return deserializeMixedResults(closePipeline, resultSerializer, hashKeySerializer, hashValueSerializer);
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}
}
});
}
In cases like this, it should help to specify the type explicitly:
redisTemplate1.executePipelined({ connection =>
YourCode…
}: RedisCallback[String], redisTemplate1.getValueSerializer)
Note the type ascription : RedisCallback[String].

How to construct a dynamic where filter in EF.Core to handle equals, LIKE, gt, lt, etc

Please how do we construct a dynamic where filter in EF.Core to handle:
Query.Where(fieldName, compareMode, value)
I basically Expect to use it like below:
[HttpGet(Name = nameof(GetStaff))]
public IActionResult GetStaffAsync([FromQuery] QueryParams p)
{
var s = db.Staff.AsNoTracking()
.Where(p.filter_field, p.filter_mode, p.filter_value)
.OrderByMember(p.sortBy, p.descending);
var l = new Pager<Staff>(s, p.page, p.rowsPerPage);
return Ok(l);
}
//Helpers
public class QueryParams
{
public bool descending { get; set; }
public int page { get; set; } = 1;
public int rowsPerPage { get; set; } = 5;
public string sortBy { get; set; }
public onject filter_value { get; set; }
public string filter_field { get; set; }
public string filter_mode { get; set; }
}
public class Pager<T>
{
public int pages { get; set; }
public int total { get; set; }
public IEnumerable<T> Items { get; set; }
public Pager(IEnumerable<T> items, int offset, int limit)
{
Items = items.Skip((offset - 1) * limit).Take(limit).ToList<T>();
total = items.Count();
pages = (int)Math.Ceiling((double)total / limit);
}
}
Assuming all you have is the entity type and strings representing the property, comparison operator and the value, building dynamic predicate can be done with something like this:
public static partial class ExpressionUtils
{
public static Expression<Func<T, bool>> BuildPredicate<T>(string propertyName, string comparison, string value)
{
var parameter = Expression.Parameter(typeof(T), "x");
var left = propertyName.Split('.').Aggregate((Expression)parameter, Expression.Property);
var body = MakeComparison(left, comparison, value);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
private static Expression MakeComparison(Expression left, string comparison, string value)
{
switch (comparison)
{
case "==":
return MakeBinary(ExpressionType.Equal, left, value);
case "!=":
return MakeBinary(ExpressionType.NotEqual, left, value);
case ">":
return MakeBinary(ExpressionType.GreaterThan, left, value);
case ">=":
return MakeBinary(ExpressionType.GreaterThanOrEqual, left, value);
case "<":
return MakeBinary(ExpressionType.LessThan, left, value);
case "<=":
return MakeBinary(ExpressionType.LessThanOrEqual, left, value);
case "Contains":
case "StartsWith":
case "EndsWith":
return Expression.Call(MakeString(left), comparison, Type.EmptyTypes, Expression.Constant(value, typeof(string)));
default:
throw new NotSupportedException($"Invalid comparison operator '{comparison}'.");
}
}
private static Expression MakeString(Expression source)
{
return source.Type == typeof(string) ? source : Expression.Call(source, "ToString", Type.EmptyTypes);
}
private static Expression MakeBinary(ExpressionType type, Expression left, string value)
{
object typedValue = value;
if (left.Type != typeof(string))
{
if (string.IsNullOrEmpty(value))
{
typedValue = null;
if (Nullable.GetUnderlyingType(left.Type) == null)
left = Expression.Convert(left, typeof(Nullable<>).MakeGenericType(left.Type));
}
else
{
var valueType = Nullable.GetUnderlyingType(left.Type) ?? left.Type;
typedValue = valueType.IsEnum ? Enum.Parse(valueType, value) :
valueType == typeof(Guid) ? Guid.Parse(value) :
Convert.ChangeType(value, valueType);
}
}
var right = Expression.Constant(typedValue, left.Type);
return Expression.MakeBinary(type, left, right);
}
}
Basically building property accessor (with nested property support), parsing the comparison operator and calling the corresponding operator/method, dealing with from/to string and from/to nullable type conversions. It can be extended to handle EF Core specific functions like EF.Functions.Like by adding the corresponding branch.
It can be used directly (in case you need to combine it with other predicates) or via custom extension method like this:
public static partial class QueryableExtensions
{
public static IQueryable<T> Where<T>(this IQueryable<T> source, string propertyName, string comparison, string value)
{
return source.Where(ExpressionUtils.BuildPredicate<T>(propertyName, comparison, value));
}
}
based on Ivans answer this is what i came up with
public static class ExpressionUtils
{
public static Expression<Func<T, bool>> BuildPredicate<T>(string propertyName, string comparison, object value)
{
var parameter = Expression.Parameter(typeof(T));
var left = propertyName.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);
var body = MakeComparison(left, comparison, value);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
static Expression MakeComparison(Expression left, string comparison, object value)
{
var constant = Expression.Constant(value, left.Type);
switch (comparison)
{
case "==":
return Expression.MakeBinary(ExpressionType.Equal, left, constant);
case "!=":
return Expression.MakeBinary(ExpressionType.NotEqual, left, constant);
case ">":
return Expression.MakeBinary(ExpressionType.GreaterThan, left, constant);
case ">=":
return Expression.MakeBinary(ExpressionType.GreaterThanOrEqual, left, constant);
case "<":
return Expression.MakeBinary(ExpressionType.LessThan, left, constant);
case "<=":
return Expression.MakeBinary(ExpressionType.LessThanOrEqual, left, constant);
case "Contains":
case "StartsWith":
case "EndsWith":
if (value is string)
{
return Expression.Call(left, comparison, Type.EmptyTypes, constant);
}
throw new NotSupportedException($"Comparison operator '{comparison}' only supported on string.");
default:
throw new NotSupportedException($"Invalid comparison operator '{comparison}'.");
}
}
}
and some tests
public class Tests
{
[Fact]
public void Nested()
{
var list = new List<Target>
{
new Target
{
Member = "a"
},
new Target
{
Member = "bb"
}
};
var result = list.AsQueryable()
.Where(ExpressionUtils.BuildPredicate<Target>("Member.Length", "==", 2))
.Single();
Assert.Equal("bb", result.Member);
}
[Fact]
public void Field()
{
var list = new List<TargetWithField>
{
new TargetWithField
{
Field = "Target1"
},
new TargetWithField
{
Field = "Target2"
}
};
var result = list.AsQueryable()
.Where(ExpressionUtils.BuildPredicate<TargetWithField>("Field", "==", "Target2"))
.Single();
Assert.Equal("Target2", result.Field);
}
[Theory]
[InlineData("Name", "==", "Person 1", "Person 1")]
[InlineData("Name", "!=", "Person 2", "Person 1")]
[InlineData("Name", "Contains", "son 2", "Person 2")]
[InlineData("Name", "StartsWith", "Person 2", "Person 2")]
[InlineData("Name", "EndsWith", "son 2", "Person 2")]
[InlineData("Age", "==", 13, "Person 2")]
[InlineData("Age", ">", 12, "Person 2")]
[InlineData("Age", "!=", 12, "Person 2")]
[InlineData("Age", ">=", 13, "Person 2")]
[InlineData("Age", "<", 13, "Person 1")]
[InlineData("Age", "<=", 12, "Person 1")]
public void Combos(string name, string expression, object value, string expectedName)
{
var people = new List<Person>
{
new Person
{
Name = "Person 1",
Age = 12
},
new Person
{
Name = "Person 2",
Age = 13
}
};
var result = people.AsQueryable()
.Where(ExpressionUtils.BuildPredicate<Person>(name, expression, value))
.Single();
Assert.Equal(expectedName, result.Name);
}
}
I modified the answer I found here: Linq WHERE EF.Functions.Like - Why direct properties work and reflection does not?
I chucked together a version for those using NpgSQL as their EF Core provider as you will need to use the ILike function instead if you want case-insensitivity, also added a second version which combines a bunch of properties into a single Where() clause:
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName, string searchTerm)
{
// Check property name
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentNullException(nameof(propertyName));
}
// Check the search term
if(string.IsNullOrEmpty(searchTerm))
{
throw new ArgumentNullException(nameof(searchTerm));
}
// Check the property exists
var property = typeof(T).GetProperty(propertyName);
if (property == null)
{
throw new ArgumentException($"The property {typeof(T)}.{propertyName} was not found.", nameof(propertyName));
}
// Check the property type
if(property.PropertyType != typeof(string))
{
throw new ArgumentException($"The specified property must be of type {typeof(string)}.", nameof(propertyName));
}
// Get expression constants
var searchPattern = "%" + searchTerm + "%";
var itemParameter = Expression.Parameter(typeof(T), "item");
var functions = Expression.Property(null, typeof(EF).GetProperty(nameof(EF.Functions)));
var likeFunction = typeof(NpgsqlDbFunctionsExtensions).GetMethod(nameof(NpgsqlDbFunctionsExtensions.ILike), new Type[] { functions.Type, typeof(string), typeof(string) });
// Build the property expression and return it
Expression selectorExpression = Expression.Property(itemParameter, property.Name);
selectorExpression = Expression.Call(null, likeFunction, functions, selectorExpression, Expression.Constant(searchPattern));
return source.Where(Expression.Lambda<Func<T, bool>>(selectorExpression, itemParameter));
}
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, IEnumerable<string> propertyNames, string searchTerm)
{
// Check property name
if (!(propertyNames?.Any() ?? false))
{
throw new ArgumentNullException(nameof(propertyNames));
}
// Check the search term
if (string.IsNullOrEmpty(searchTerm))
{
throw new ArgumentNullException(nameof(searchTerm));
}
// Check the property exists
var properties = propertyNames.Select(p => typeof(T).GetProperty(p)).AsEnumerable();
if (properties.Any(p => p == null))
{
throw new ArgumentException($"One or more specified properties was not found on type {typeof(T)}: {string.Join(",", properties.Where(p => p == null).Select((p, i) => propertyNames.ElementAt(i)))}.", nameof(propertyNames));
}
// Check the property type
if (properties.Any(p => p.PropertyType != typeof(string)))
{
throw new ArgumentException($"The specified properties must be of type {typeof(string)}: {string.Join(",", properties.Where(p => p.PropertyType != typeof(string)).Select(p => p.Name))}.", nameof(propertyNames));
}
// Get the expression constants
var searchPattern = "%" + searchTerm + "%";
var itemParameter = Expression.Parameter(typeof(T), "item");
var functions = Expression.Property(null, typeof(EF).GetProperty(nameof(EF.Functions)));
var likeFunction = typeof(NpgsqlDbFunctionsExtensions).GetMethod(nameof(NpgsqlDbFunctionsExtensions.ILike), new Type[] { functions.Type, typeof(string), typeof(string) });
// Build the expression and return it
Expression selectorExpression = null;
foreach (var property in properties)
{
var previousSelectorExpression = selectorExpression;
selectorExpression = Expression.Property(itemParameter, property.Name);
selectorExpression = Expression.Call(null, likeFunction, functions, selectorExpression, Expression.Constant(searchPattern));
if(previousSelectorExpression != null)
{
selectorExpression = Expression.Or(previousSelectorExpression, selectorExpression);
}
}
return source.Where(Expression.Lambda<Func<T, bool>>(selectorExpression, itemParameter));
}

web.api only serializing hidden fields

I'm experiencing a strange behaviour.
My web.api is returning only hiddenfields from my ObjectCollection on a GET request.
This is my controller:
// GET: api/UserDocuments
[Route("api/UserDocuments/User/{userName}")]
public List<DocIndex> Get(string userName)
{
User usuari = Humanisme.User.LoadByUserName(userName);
List<DocIndex> resposta = DocumentCollection.LoadIndexPerUsuari(usuari);
return resposta;
}
And this is the object as it gets generated from the BOM:
namespace Humanisme
{
using CodeFluent.Runtime;
using CodeFluent.Runtime.Utilities;
// CodeFluent Entities generated (http://www.softfluent.com). Date: Tuesday, 01 March 2016 11:52.
// Build:1.0.61214.0820
[System.CodeDom.Compiler.GeneratedCodeAttribute("CodeFluent Entities", "1.0.61214.0820")]
[System.SerializableAttribute()]
[System.ComponentModel.DataObjectAttribute()]
public partial class DocIndex : CodeFluent.Runtime.ICodeFluentLightEntity
{
private int _id = -1;
[System.NonSerializedAttribute()]
private Humanisme.User _user = ((Humanisme.User)(null));
private string _lat = default(string);
private string _lon = default(string);
private string _etapaVital = default(string);
private string _solvencia = default(string);
private int _valoracio = CodeFluentPersistence.DefaultInt32Value;
private System.DateTime _data = CodeFluentPersistence.DefaultDateTimeValue;
private string _nom = default(string);
public DocIndex()
{
}
[System.ComponentModel.DefaultValueAttribute(((int)(-1)))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=false, Type=typeof(int))]
[System.ComponentModel.DataObjectFieldAttribute(true)]
public int Id
{
get
{
return this._id;
}
set
{
this._id = value;
}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public Humanisme.User User
{
get
{
return this._user;
}
set
{
this._user = value;
}
}
[System.ComponentModel.DefaultValueAttribute(default(string))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Type=typeof(string))]
public string Lat
{
get
{
return this._lat;
}
set
{
this._lat = value;
}
}
[System.ComponentModel.DefaultValueAttribute(default(string))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Type=typeof(string))]
public string Lon
{
get
{
return this._lon;
}
set
{
this._lon = value;
}
}
[System.ComponentModel.DefaultValueAttribute(default(string))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Type=typeof(string))]
public string EtapaVital
{
get
{
return this._etapaVital;
}
set
{
this._etapaVital = value;
}
}
[System.ComponentModel.DefaultValueAttribute(default(string))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Type=typeof(string))]
public string Solvencia
{
get
{
return this._solvencia;
}
set
{
this._solvencia = value;
}
}
[System.ComponentModel.DefaultValueAttribute(CodeFluentPersistence.DefaultInt32Value)]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=false, Type=typeof(int))]
public int Valoracio
{
get
{
return this._valoracio;
}
set
{
this._valoracio = value;
}
}
[System.Xml.Serialization.XmlElementAttribute(IsNullable=false, Type=typeof(System.DateTime))]
public System.DateTime Data
{
get
{
return this._data;
}
set
{
this._data = value;
}
}
[System.ComponentModel.DefaultValueAttribute(default(string))]
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Type=typeof(string))]
public string Nom
{
get
{
return this._nom;
}
set
{
this._nom = value;
}
}
protected virtual void ReadRecord(System.Data.IDataReader reader, CodeFluent.Runtime.CodeFluentReloadOptions options)
{
if ((reader == null))
{
throw new System.ArgumentNullException("reader");
}
if ((((options & CodeFluent.Runtime.CodeFluentReloadOptions.Properties)
== 0)
== false))
{
this._id = CodeFluentPersistence.GetReaderValue(reader, "Id", ((int)(-1)));
this._user = new Humanisme.User();
CodeFluent.Runtime.CodeFluentLightWeightPersistence.ReadRecord(reader, this._user, null, new CodeFluent.Runtime.Utilities.Pair<string, string>("Id", "User_Id"));
this._lat = CodeFluentPersistence.GetReaderValue(reader, "Lat", ((string)(default(string))));
this._lon = CodeFluentPersistence.GetReaderValue(reader, "Lon", ((string)(default(string))));
this._etapaVital = CodeFluentPersistence.GetReaderValue(reader, "EtapaVital", ((string)(default(string))));
this._solvencia = CodeFluentPersistence.GetReaderValue(reader, "Solvencia", ((string)(default(string))));
this._valoracio = CodeFluentPersistence.GetReaderValue(reader, "Valoracio", ((int)(CodeFluentPersistence.DefaultInt32Value)));
this._data = CodeFluentPersistence.GetReaderValue(reader, "Data", ((System.DateTime)(CodeFluentPersistence.DefaultDateTimeValue)));
this._nom = CodeFluentPersistence.GetReaderValue(reader, "Nom", ((string)(default(string))));
}
}
void CodeFluent.Runtime.ICodeFluentLightEntity.ReadRecord(System.Data.IDataReader reader)
{
this.ReadRecord(reader, CodeFluent.Runtime.CodeFluentReloadOptions.Default);
}
}
}
Calling the web.api get method returns this JSON:
[
{
"_id": 1,
"_lat": null,
"_lon": null,
"_etapaVital": null,
"_solvencia": null,
"_valoracio": 0,
"_data": "0001-01-01T00:00:00",
"_nom": null
}
]
Serializer (from WebApiConfig.cs)
JsonMediaTypeFormatter jsonFormatter = (JsonMediaTypeFormatter)config.Formatters.FirstOrDefault(f => f is JsonMediaTypeFormatter);
if (jsonFormatter != null)
{
// jsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Include;
jsonFormatter.UseDataContractJsonSerializer = true;
}
The classes generated by CodeFluent Entities are decorated by SerializableAttribute. This attribute changes the way Json.NET serialize or deserialize the object. You can configure Json.NET to ignore this attribute:
JsonMediaTypeFormatter jsonFormatter = (JsonMediaTypeFormatter)config.Formatters.FirstOrDefault(f => f is JsonMediaTypeFormatter);
if (jsonFormatter != null)
{
jsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableAttribute = true
};
}
http://james.newtonking.com/archive/2012/04/11/json-net-4-5-release-2-serializable-support-and-bug-fixes
Json.NET now detects types that have the SerializableAttribute and serializes all the fields on that type, both public and private, and ignores the propertie
So you can use the service producer which will add the DataMemberAttribute or you can use the Json.NET Aspect to automatically add specific Json.NET attribute: Newtonsoft.Json.JsonObjectAttribute and Newtonsoft.Json.JsonPropertyAttribute.
Finally found!
When dealing with web.api never, never, never forget to add the "Service Producer" subproducer attached to the standard BOM Producer in your model project.
You'll never notice any problem but at serializing when no attributes will be processed and only hidden properties (object fields) will be serialized at output.
Sorry for the nerd mistake, happy for the lesson learned.
Again, thanks Meziantou. You would never figured where the issue was originated, mainly because I didn't carried all the project details to the question.

How to store user sql where clause, and how to apply it on a select?

I am using JPA / Eclipselink / PostgreSQL within my application.
I have a model that list some data, and I would like to let the user of the application to create his own where clause parameters.
How can I store theses parameters ? as plain sql string ?
Then how can I apply the where clause ? as a simple string concatenation ? (I don't like this idea at all).
Bests regards.
Ok, so I solved my problem.
For information : I have created a recursive JSON representation of every where clause parameters possibility.
And I have created a query using criteria api by decoding the pojo structure from json.
The json class look like that :
public class JSonSearchCriteria
{
public static enum CriteriaType
{
asc,
desc,
count,
countDistinct,
and,
or,
not,
equal,
notEqual,
between,
gt,
ge,
lt,
le,
like,
notLike;
}
#Expose
public CriteriaType type;
#Expose
public List<JSonSearchCriteria> sub;
#Expose
public String what = null;
#Expose
public List<Integer> integerValue = null;
#Expose
public List<Long> longValue = null;
#Expose
public List<Boolean> booleanValue = null;
#Expose
public List<String> stringValue = null;
#Expose
public List<DateTime> datetimeValue = null;
public JSonSearchCriteria()
{
}
public JSonSearchCriteria(final CriteriaType type)
{
this.type = type;
}
public JSonSearchCriteria(final CriteriaType type, final String what)
{
this(type);
this.what = what;
}
public JSonSearchCriteria(final CriteriaType type, final String what, final String... values)
{
this(type, what);
for(final String value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final Long... values)
{
this(type, what);
for(final Long value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final Integer... values)
{
this(type, what);
for(final Integer value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final DateTime... values)
{
this(type, what);
for(final DateTime value : values)
{
value(value);
}
}
public void add(final JSonSearchCriteria subCriteria)
{
if(sub == null)
{
sub = new ArrayList<>();
}
sub.add(subCriteria);
}
public void value(final String value)
{
if(stringValue == null)
{
stringValue = new ArrayList<>();
}
stringValue.add(value);
}
public void value(final Long value)
{
if(longValue == null)
{
longValue = new ArrayList<>();
}
longValue.add(value);
}
public void value(final Integer value)
{
if(integerValue == null)
{
integerValue = new ArrayList<>();
}
integerValue.add(value);
}
public void value(final DateTime value)
{
if(datetimeValue == null)
{
datetimeValue = new ArrayList<>();
}
datetimeValue.add(value);
}
#SuppressWarnings(
{
"unchecked", "rawtypes"
})
#Transient
public Predicate buildPredicate(final CriteriaBuilder builder, final Root<Record> root, Join<Record, RecordInfo> infos)
{
switch(type)
{
case and:
case or:
final Predicate[] preds = new Predicate[sub.size()];
int cpt = 0;
for(final JSonSearchCriteria s : sub)
{
preds[cpt] = s.buildPredicate(builder, root, infos);
cpt++;
}
if(type == CriteriaType.and)
{
return builder.and(preds);
}
else if(type == CriteriaType.or)
{
return builder.or(preds);
}
break;
case equal:
case lt:
case gt:
case between:
final Path p;
if(what.startsWith("infos."))
{
p = infos.get(what.substring(6));
}
else
{
p = root.get(what);
}
if(stringValue != null && !stringValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, stringValue.get(0));
}
}
else if(longValue != null && !longValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, longValue.get(0));
}
else if(type == CriteriaType.lt)
{
return builder.lt(p, longValue.get(0));
}
else if(type == CriteriaType.gt)
{
return builder.gt(p, longValue.get(0));
}
}
else if(integerValue != null && !integerValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, integerValue.get(0));
}
else if(type == CriteriaType.lt)
{
return builder.lt(p, integerValue.get(0));
}
else if(type == CriteriaType.gt)
{
return builder.gt(p, integerValue.get(0));
}
}
else if(booleanValue != null && !booleanValue.isEmpty())
{
return builder.equal(p, booleanValue.get(0));
}
else if(datetimeValue != null && !datetimeValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, datetimeValue.get(0));
}
else if(type == CriteriaType.between && datetimeValue.size() > 1)
{
return builder.between(p, datetimeValue.get(0), datetimeValue.get(1));
}
}
break;
}
System.err.println(type + " - not implemented");
return null;
}
}
And it is used like that :
final SearchTemplate templ = DBHelper.get(SearchTemplate.class, 100);
final Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeJsonAdapter()).create();
final JSonSearchCriteria crits = gson.fromJson(templ.getTemplate(), JSonSearchCriteria.class);
final CriteriaBuilder critBuilder = DBHelper.getInstance().em().getCriteriaBuilder();
final CriteriaQuery<Record> critQuery = critBuilder.createQuery(Record.class);
final Root<Record> root = critQuery.from(Record.class);
final Join<Record, RecordInfo> infos = root.join("infos");
critQuery.where(crits.buildPredicate(critBuilder, root, infos));
final TypedQuery<Record> query = DBHelper.getInstance().em().createQuery(critQuery);
final List<Record> result = query.getResultList();
for(final Record rec : result)
{
System.err.println(rec.toString());
}

getmethod(methodname,new[]Type) in Type arrays contains ref parameter and method is overrided

For example
class xx
{
public string name
{
get {return "";}
}
}
class yy
{
public string name(string n)
{
return "";
}
public string name(string n,ref string m)
{
return "";
}
public string name(string n,string m,ref xx k)
{
return "";
}
}
How to get "name" method by reflection technology ?
There's no easy way to do it using GetMethod. However, you can easily do it with GetMethods and Linq :
var methodInfo = from m in typeof(yy).GetMethods()
where m.Name == "name"
let prms = m.GetParameters()
where prms.Length == 3
&& prms[0].ParameterType == typeof(string)
&& prms[1].ParameterType == typeof(string)
&& prms[2].ParameterType == typeof(xx).MakeByRefType()
select m;
You could use Type.MakeByRefType()-Method to create an ref type param. The rest is done by reflection classes.
var method = typeof(yy).GetMethod(
"name",
new[] {typeof(string), typeof(string).MakeByRefType()});