I have a map of binding values:
final Map<String, Object> values = ...;
Before executing the query, I loop through the binding parameters and bind its value as following:
final ResultQuery<Record> q = ...;
for (final Param p : q.getParams().values()) {
if (p.getParamName() != null) {
q.bind(p.getParamName(), values.get(p.getParamName()));
}
}
When the same binding is used multiple times, this seems to fail:
final ResultQuery<Record> q = create.select().from(DSL.table("my_table"))
.where((DSL.field("identifier").eq(DSL.param("binding"))
.and(DSL.field("identifier").eq(DSL.param("binding")))));
... code above ...
create.fetch(q);
In the generated query, only one of the bindings is filled in. The other is null.
Is there an alternative approach? The same binding parameter can only be used once, or is this a bug?
(I know this query doesn't make much sense, it is only for demonstrating the problem.)
The issue was probably solved if we could do the following instead, but it is not possible since getParams() returns Param<?> and not Param<Object>:
for (final Param p : q.getParams().values()) {
if (p.getParamName() != null) {
p.bind(values.get(p.getParamName()));
}
}
update - The statement above is incorrect, since getParams() returns a Map<String, Param> and not Map<String, Collection<Param>>. It still woud be useful to bind a Param directly though.
This is a bug in jOOQ 3.5.2 (#4056).
Another workaround apart from the one you've found would be to make sure that both instances of "binding" are in fact the same, you should probably externalise the bind value:
Param<Object> binding = DSL.param("binding");
final ResultQuery<Record> q = create.select().from(DSL.table("my_table"))
.where((DSL.field("identifier").eq(binding)
.and(DSL.field("identifier").eq(binding))));
Now, you'll explicitly create a single bind value that is used two times in the AST.
Related
I am having very weird situation here , In my project we have Architecture Rules Test. but this below method did not throw any error msg , but when I just change a method passing meter from String to Query and change the first line of the method then it is throwing
Architecture Violation [Priority: MEDIUM] - Rule exception, (the rule is set to check if we are importing any third party library class in our specific class which for biddable and we have written IT for the same so no one should use third part library lets say classes from com.google.* here since I am using here ArrayListMultimap from com.google.common.. so this is failing , but the real question here is why it is happening when I am changing the parameter and why it was working fine earlier , this rule is breaking after I made changes in just parameter I did not add the class in ArrayListMultimap in this map and error is coming like I am using ArrayListMultimap .create() method ehich is breaking the rule )
Because the package this method is present(let's package P) is not supposed to depend on the classes present in packages ['com.google.common..', 'com.google.thirdparty..']'.
And ArrayListMultimap<String, Integer> xAndYMap = ArrayListMultimap.create(); this from google package. Here my doubt is why it is working if I dont change the method passing parameter type (first it was String then I changed from String -> Query).
I am not able to resolve it. What am I supposed to do here , is this happening because I changed function def by changing passing parameter? or if it is so why it was working and building the project successfully.
Could anyone please help here to understand the situation ?
Thanks in advance:)
the Method is given below:
private Map<CONSTANT_X, List<Integer>> getAllOfCaseCountGroupMap(final Query query) {
List<Object[]> results = this.getQueryResultsAsList(query);
Map<CONSTANT_X, List<Integer>> result = new HashMap<>();
ArrayListMultimap<String, Integer> xAndYMap = ArrayListMultimap.create();
for (Object[] objs : results) {
CONSTANT_X x = CONSTANT_X.valueOf(objs[0].toString());
Integer caseId = (Integer) objs[1];
xAndYMap.put(x.toString(), caseId);
}
for (String key : xAndYMap.keys()) {
CONSTANT_X x = CONSTANT_X.valueOf(key);
List<Integer> y = xAndYMap.get(key);
result.put(x, y);
}
return result;
}`enter code here`
I'm writing a simple skill similart to the java airplane facts sample and I have two strange behaviours:
1) the same code in one intent works correctly, but in another causes an error;
2) I can't remove an element from a public static List!
I will try to explain better with a very close example.
I have two Intents that we can call:
- ActionIntent;
- StopIntent.
The first intent retrieves a list (of type List) retrieved from a class Constants and returns an attribute of a random CustomObject --
this works correctly.
Then it should set the object to Session Attributes and remove it from the list, because the next time the response should be a second attribute of the last CustomObject plus the first attribute of the new CustomObject. Does it make sense?
Here is the code:
// this row works correctly on the other intent
Map<String, Object> sessionAttributes = input.getAttributesManager().getSessionAttributes();
CustomObject last=(sessionAttributes.get("last")!=null) ? (CustomObject)sessionAttributes.get("last") : null;
List<CustomObject> allObjects = MAPPER.convertValue(Constants.getAllObjects(), List.class);
int index = new Random().nextInt(tutti.size());
CustomObject new = allObjects.get(index);
// a simple method that contains allObjects.remove(index) because it didn't work here but also this cause an error
Constants.removeCustomObjectFromList(index);
sessionAttributes.put("ultimoNome", nuovoNome);
String title = Constants.SKILL_TITLE;
String primaryText =new.getTrue();
String secondaryText =(last!=null) ?last.getFalse() : "";
String speechText = "" + secondaryText + " "+primaryText + "?";
return input.getResponseBuilder()
.withSpeech(speechText)
.withSimpleCard(title, primaryText)
.withReprompt(speechText)
.build();
If I comment out the rows linked to the sessionAttribute and the Constants.removeCustomObjectFromList it works correctly but, as I said, the reference to sessionAttribute works correctly in another intent and I must remove CustomObjects from my initial list because the user should listen two time the same thing!
Could someone tell me where to find good info on this subject?
https://ask-sdk-for-nodejs.readthedocs.io/en/latest/Managing-Attributes.html
Above is the official docs. It can be a bit difficult to understand a couple things in there due to lack of extensive explanation, but for the most part everything you need is there. As for your issue, I don't know if this is the only cause, but I don't think getAttributesManager() is a function, unless that's something you've defined. Your code:
Map<String, Object> sessionAttributes = input.getAttributesManager().getSessionAttributes();
Can you try:
Map<String, Object> sessionAttributes = input.attributesManager.getSessionAttributes();
instead?
I'm working on an application with spring-ibatis integration in which I have to log some of the query performed. So what I'd like to do, is basically getting the SQL from the ibatis mapped statements in the XML config file and then add somehow the parameters. I've been able to get the query with this lines of code:
MappedStatement ms = (MappedStatement) ((SqlMapClientImpl) sqlMapClient)
.getDelegate().getMappedStatement(queryId);
ms.setParameterClass(HashMap.class);
RequestScope scope = new RequestScope();
scope.setStatement(ms);
String sql = ((DynamicSql) ms.getSql()).getSql(scope, params);
So with the first row I get the MappedStatement and with the last one I get the raw query. The problem is that even if I'm passing to it the object with the query parameters, the SQL still has the parameters placeholders '?' (in the XML query they are named parameters, not positionals).
I have tried to set the parameterClass field instead of the parameterMap as suggested here but with no success. I'm not sure on how to work with the inline parameters.
I'm using ibatis-sqlmap 2.3.0 and spring-ibatis 2.0.8.
As you have probably noticed I have little to no knowledge of iBatis. Also, please I know that this is dirty and that I'm using classes that I'm not supposed to, no need to point that out.
Thank you for the help.
I've solved this problem and I want to share the solution for future readers that may have the same issue. Before doing that, keep in mind that this is NOT the way you should work with iBatis but only a dirty workaround to get the underlying SQL.
First of all, we need to group iBatis queries in at least 2 groups:
Static queries, they are simple mapped statements without any conditional elements.
Dynamic queries, they are mapped statements with conditional elements (e.g. isEqual, isGreaterThan, isNull...).
Once you have done this difference, here's the code to get the SQL:
public static String getSQLFromDynamicQuery(SqlMapClient sqlMapClient,
String queryId, Object paramObject) {
// Gets the SQL and parameters.
MappedStatement ms = ((SqlMapClientImpl) sqlMapClient).getDelegate()
.getMappedStatement(queryId);
RequestScope scope = new RequestScope();
scope.setStatement(ms);
String sql = ((DynamicSql) ms.getSql()).getSql(scope, paramObject);
Object[] params = ms.getSql().getParameterMap(scope, paramObject)
.getParameterObjectValues(scope, paramObject);
// Adds params to the query.
return bindQueryParam(sql, params);
}
public String getSQLFromStaticQuery(SqlMapClient sqlMapClient,
String queryId, Object... params) {
// Gets the SQL.
String sql = ((StaticSql) ((SqlMapClientImpl) sqlMapClient)
.getDelegate().getMappedStatement(queryId).getSql()).getSql(
null, null);
// Adds params to the query.
if (params != null) {
sql = bindQueryParam(sql, params);
}
return sql;
}
public static String bindQueryParam(String sql, Object... params) {
String result = sql;
for (Object param : params) {
result = result.replaceFirst("\\?",
param == null ? "null" : param.toString());
}
return result;
}
The bindQueryParam method replaces the question marks in the query with an array of object. For a static query, you will have to pass that array meanwhile for the dynamic one you can pass an Object or a java.util.Map, according to what is your parameterClass of the Mapped Statement.
Both methods use explicit subcasting (I've spent a lot of time looking at the source code to figure out how to make this work as you can imagine), so you may want to pay attention to call the right method according to the Mapped Statement you are processing or you will get a ClassCastException.
Again, this is not the recommended way but it works if you need it.
I'm building something of a relay server, using JAX-RS. I need to be able to extract any query parameters from a GET request and then re-wrap them into another request, to pass along to another server. I'm unfamiliar with MultivaluedMap, but I just figured out what is happening. The UriInfo class's getQueryParameters method returns a MultivaluedMap<String, String>. What bit me, unexpectedly, is that the values of each parameter are List values, even though they purport to be String values (by the way I read the JavaDoc).
In other words, if I have a key-value pair of foo=bar, in the URL query string, when I extract the parameter, it comes out as foo=[bar]. This totally throws me for a loop (a 500 Server Error, actually) when I try to re-wrap the parameter and send it along to the other server.
Is there another way to handle unpacking the query string from a Request, and then re-packing it for another Request? I'm including some code to illustrate my issue:
#GET
#Path("parameters")
public Response showParameters(#Context UriInfo uriInfo) {
MultivaluedMap<String, String> parameters = uriInfo.getQueryParameters();
StringBuffer sb = new StringBuffer();
sb.append("<h4>Parameters:</h4>");
if (parameters != null) {
sb.append("<ul>");
Iterator it = parameters.keySet().iterator();
while (it.hasNext()) {
String key = (String)it.next();
sb.append("<li>")
.append(key)
.append(": ")
.append(parameters.get(key))
.append("</li>");
}
sb.append("</ul>");
}
else {
sb.append("<p>None</p>");
}
return Response.ok(sb.toString()).build();
}
So, in summary, what gets printed out from the code above, if the request has query parameters, is something like this:
Parameters:
key1: [value1]
key2: [value2]
key3: [value3]
Is there another way to unpack/re-pack, and maybe avoid this whole issue altogether? Thanks.
Complete answer
#Jack deserves credit for pointing me in the right direction, and I am marking his answer as correct, but here is what I got working.
Client client = ClientBuilder.newClient();
// Assume instance variable providing URI (without query string).
WebTarget target = client.target(theRequestUri);
// Instance variable uriInfo.
MultivaluedMap<String, String> parameters = uriInfo.getQueryParameters();
if (parameters != null && parameters.size() > 0) {
Iterator it = parameters.keySet().iterator();
String key = null;
StringTokenizer st = null;
while (it.hasNext()) {
key = (String)it.next();
// RESTEasy API is quirky, here. It wraps the values in square
// brackets; moreover, each value is separated by a comma and
// padded by a space as well. ([one, two, three, etc])
st = new StringTokenizer(parameters.get(key).toString(), "[,]");
while (st.hasMoreTokens()) {
target = target.queryParam(key, st.nextToken().trim());
}
}
}
// Instance method: getContentType.
Response response = target.request().accept(getContentType()).get();
Its because of MultivaluedMap interface.
public interface MultivaluedMap<K, V> extends Map<K, List<V>> {
It returns the values as List.
Instead of parameters.get(key) try parameters.getFirst(key)
Note that this will drop the other values for the same parameter. It is possible to send multiple values for same parameter while making a rest call such as blahblah:8080?foo=bar1&foo=bar2. With getFirst() call you will get bar1 value only. If you are sure you will not get multiple calls, you can go with getFirst(key) approach
--- UPDATED ---
Based on your comments, it seems you need to iterate over the multivalued map and call queryParam on the WebTarget instance. I understand you are looking for a library/straight forward way to do this. I did not try RESTEasy. But code I believe should be simple enough.
multiValuesMap?.each { key, values->
webTargetInstance = webTargetInstance.queryParam(key, values as Object[])
}
With Deadbolt's module we can check the restrictedResource with a ressource name and parameters in the view.
For example in my view, I have it, and it works well:
#{deadbolt.restrictedResource resourceKeys:['Domain'] , resourceParameters:['domainid':domain.id]}
<li>${domain.title}</li>
#{/deadbolt.restrictedResource}
But in my controller, I just can check the ressource name but I don't find a way to check it in my RestrictedResourcesHandler passing the domainid with.
I am looking for a solution to do something like that:
#RestrictedResource(name = {"Domain"}, params = {domainid})
public static void showDomain(String domainid)
{
}
Thanks in advance
It's not possible to have dynamic information in an annotation, but you can use params to define the name of an incoming value in the request. However, this information isn't passed into the handler at the moment because it expects a map. While you can pass in a map of parameters from the restrictedResource tag, you can't do this from an annotation so an empty map is passed into the handler.
Your best approach here is to pull a well-known parameter name from the request object. I need to have a rethink about the best way to do this without breaking backwards compatibility.
Steve (author of Deadbolt)
I've found a way the solved the problem, not the best I think, but it is the Steve Chaloner's solution (Deadbolt's creator), and it works.
For example, if your Controller's method argument is named "id", and you want to check this id inside your checkAccess method :
// Controller's method :
#RestrictedResource(name = {"Domain"})
public static void showDomain(String id){}
Just check at the beginning of your checkAccess method the Map "resourceParameters" is empty, and use the request object to get the parameters:
public AccessResult checkAccess(List<String> resourceNames,
Map<String, String> resourceParameters)
{
Map<String, String> hashm = new HashMap<String,String>();
if(resourceParameters != null && !resourceParameters.isEmpty()){
hashm = resourceParameters;
}else if(Http.Request.current().routeArgs!= null && !Http.Request.current().routeArgs.isEmpty()){
hashm = Http.Request.current().routeArgs;
}
}
Then just have to foreach your hashmap inside your checkAccess method to get your Controller's method argument and check the Access as you wish.
for (Map.Entry<String,String> mp : hashm.entrySet())
{
// Get the id argument
if(mp.getKey().equals("id"))
{
// Do something with the value..
mp.getValue()
}
}