RESTFUL Web Service using multiple arguments - jax-rs

I have a class with my getters and setters, containing values, for example:
String value1;
String value2;
double result;
I want to use these two strings to determine what should happen with the result. If value1 equals "one" and value2 = "two" then the result should be multiplied by a predefined value.
#GET
#Path("/{value1}/{value2}/{result}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public double getResult() {
Something mon = new Something();
mon.setOne(22.2);
mon.setTwo(11.1);
if("/{value1}".equals("one")){
//multiply by mon.setOne;
}
return 0;
}
How do I read and access the values defined in the path?

If you want to receive the values as path parameters (like /foo/one/two/something), you can use #PathParam:
#GET
#Path("/foo/{value1}/{value2}/{result}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public double getResult(#PathParam("value1") String value1,
#PathParam("value2") String value2,
#PathParam("result") String result) {
...
}
But, depending on what you intend to do, you could consider using query parameters (like /foo?value1=one&value2=two&result=something) with #QueryParam:
#GET
#Path("/foo")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public double getResult(#QueryParam("value1") String value1,
#QueryParam("value2") String value2,
#QueryParam("result") String result) {
...
}
You may want to check the answers to this question for details on when to use each of them.

First of all you should use a unique API name I used /GetResult then put the parameter.
#GET
#Path("/GetResult/{value1}/{value2}/{result}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public double getResult(
#PathParam(value = "value1") String value1,
#PathParam(value = "value2") String value2,
#PathParam(value = "result") String result) {
if (value1.equals("one")) {
}
return 0;
}

Related

How to replace query parameters into intercalated url?

Hello i am want to know given a an url saved as a string with placeholders.Is there anyway to just replace the spaceholders with the desired values?
public string Constant= #"/main/url/[id]/something/[value]";
public string Replace(int id,string value)
{
string url=Replace(id,value,Constant); // "/main/url/3/something/abc"
}
As you can see the url is intercalated with variables.Is there any class provided by the framework that i could use like:
public class Replacer
{
public string FillUrl(List<object> variables,string url)
{
var fullUrl=Replace(variables,url);
return fullUrl;
}
}
You can use the String.Replace (docs):
Returns a new string in which all occurrences of a specified Unicode
character or String in the current string are replaced with another
specified Unicode character or String.
public string Replace (string oldValue, string newValue);
url = url.Replace("[id]", id.ToString()).Replace('[value]', value);

Search where A or B with querydsl and spring data rest

http://localhost:8080/users?firstName=a&lastName=b ---> where firstName=a and lastName=b
How to make it to or ---> where firstName=a or lastName=b
But when I set QuerydslBinderCustomizer customize
#Override
default public void customize(QuerydslBindings bindings, QUser user) {
bindings.bind(String.class).all((StringPath path, Collection<? extends String> values) -> {
BooleanBuilder predicate = new BooleanBuilder();
values.forEach( value -> predicate.or(path.containsIgnoreCase(value) );
});
}
http://localhost:8080/users?firstName=a&firstName=b&lastName=b ---> where (firstName=a or firstName = b) and lastName=b
It seem different parameters with AND. Same parameters with what I set(predicate.or/predicate.and)
How to make it different parameters with AND like this ---> where firstName=a or firstName=b or lastName=b ??
thx.
Your current request param are grouped as List firstName and String lastName. I see that you want to keep your request parameters without a binding, but in this case it would make your life easier.
My suggestion is to make a new class with request param:
public class UserRequest {
private String lastName;
private List<String> firstName;
// getters and setters
}
For QueryDSL, you can create a builder object:
public class UserPredicateBuilder{
private List<BooleanExpression> expressions = new ArrayList<>();
public UserPredicateBuilder withFirstName(List<String> firstNameList){
QUser user = QUser.user;
expressions.add(user.firstName.in(firstNameList));
return this;
}
//.. same for other fields
public BooleanExpression build(){
if(expressions.isEmpty()){
return Expressions.asBoolean(true).isTrue();
}
BooleanExpression result = expressions.get(0);
for (int i = 1; i < expressions.size(); i++) {
result = result.and(expressions.get(i));
}
return result;
}
}
And after you can just use the builder as :
public List<User> getUsers(UserRequest userRequest){
BooleanExpression expression = new UserPredicateBuilder()
.withFirstName(userRequest.getFirstName())
// other fields
.build();
return userRepository.findAll(expression).getContent();
}
This is the recommended solution.
If you really want to keep the current params without a binding (they still need some kind of validation, otherwise it can throw an Exception in query dsl binding)
you can group them by path :
Map<StringPath,List<String>> values // example firstName => a,b
and after that to create your boolean expression based on the map:
//initial value
BooleanExpression result = Expressions.asBoolean(true).isTrue();
for (Map.Entry entry: values.entrySet()) {
result = result.and(entry.getKey().in(entry.getValues());
}
return userRepository.findAll(result);

How to retrive #Test method parameters in #DataProvider method?

I would like to retrieve parameters name of Test method in DataProvider method.
By using method.getParameterTypes() in DataProvider, I am able to get the class of param being passed in Test method, but I want the names.
#Test
public void TC_001(String userName, String passWord){
//code goes here
}
#DataProvider
public Object[][] testData(Method method){
//Here I want to get names of param of test method i.e. userName and passWord
}
This is required because using these names I can get the data from my Excel file
You can use reflection to get the parameters from the method to get the parameter names.
#DataProvider
public Object[][] testData(Method method){
String arg0 = method.getParameters()[0].getName();
// should be "userName" in your example test case
}
Note that the classes have to be compiled with -g:vars to include the parameter names in the debug information. Otherwise parameter names are named arg0, arg1, ... It appears that with the OpenJDK 8 this is the default.
To be less dependant on that fact and to avoid possible name confusion/conflicts I'd use a (custom) annotation that specifies the argument name:
Define an annotation:
#Retention(RUNTIME)
#Target(PARAMETER)
public #interface ParamName {
public String value();
}
Use it:
public void TC_001(#ParamName("username") String userName, String passWord) { ... }
Access the name:
Parameter parameter = method.getParameters()[0];
ParamName parameterNameAnn = parameter[0].getAnnotation(ParamName.class);
String parameterName;
if (parameterNameAnn != null) {
// get the annotated name
parameterName = parameterNameAnn.value();
} else {
// annotation missing, resort to the "reflected" name
parameterName = parameter.getName();
}
See also
Reflection Tutorial (Oracle)
Especially Parameter Reflection (Oracle)
Compiler options (Oracle)
Annotation Tutorial (Oracle)

NHibernate, get rowcount when criteria have a group by

I need to get the count of rows from a criteria query and the criteria got group by projections. (needed to get paging to work)
E.g.
projectionList.Add(Projections.GroupProperty("Col1"), "col1")
.Add(Projections.CountDistinct("Col2"), "Count");
I need to avoid CreateSQL, since I have a lot of criteria.. and the restrictions etc are complex.
Can you do a subcriteria (detached) and then select count(*) from .. ? Can't figure out how?
EDIT: I solved it by getting the sql from the criteria and then modifying it so that it now works! GetSql from criteria
Not entirely sure what you want, but something like this should work (if I understand your question properly):
var subQuery = DetachedCriteria.For<SomeClass>()
.Where(... add your conditions here ...);
var count = Session.CreateCriteria<SomeClass>()
.Where(Property.ForName("Col1").In(
CriteriaTransformer.Clone(subQuery).SetProjection(Projections.Property("Col1"))
.SetProjection(Projections.Count())
.FutureValue<int>();
var results = subQuery.GetExecutableCriteria(Session)
.SetProjection(Projections.GroupProperty("Col1"), "col1"),
Projections.CountDistinct("Col2"), "Count")
).List<object[]>();
Just to think a bit outside the box and remove the query complexity from NHiberate. You can make a View for the query in the database and then make a mapping for the view.
I think this can be done by using NH Multi Queries.
Here is some stuff about it: http://ayende.com/blog/3979/nhibernate-futures Example shows how we can run query and get results count of that query in one roundtrip to the database.
And here is good answer, which sounds similar to what you want to achieve: nhibernate 2.0 Efficient Data Paging DataList Control and ObjectDataSource in which they get the result page AND total records count in one roundtrip to the database.
Also, I doubt that it is possible to read pure ##rowcount value with NH without changing sql query, as ##rowcount is database specific thing.
My assumption would be that for your case it is not possible to avoid GetSql from criteria solution, unless you simplify your query or approach. Maybe it worth to try this as well.
If you can post bigger chunk of your code, probably someone will be able to figure this out.
I 've resolved this problem on the java version (Hibernate). The problem is that the RowProjection function is some like:
count(*)
That is an aggregate function: so if you create a 'group by' property your result is a list of the grouped row and for each row you have the total count of the group.
For me, with oracle database, to make it work i've create a custom projection that, instead of create function count(*), the function is
count(count(*))
and the property in the group by clause are not written in the select ... from statement. To do that it not that simple, the problem is that you have to provide all stack to create the right sql so, with the java version I've to subclasse 2 class:
SimpleProjection
ProjectionList
After that my query generated as:
select count(*), col1, col2 from table1 group by col1, col2
become
select count(count(*)) from table1 group by col1, col2
and the result are the total row given by
select col1, col2 from table1 group by col1, col2
(usable with pagination system)
I post here the java version of the classes, if are useful for you:
public class CustomProjectionList extends ProjectionList {
private static final long serialVersionUID = 5762155180392132152L;
#Override
public ProjectionList create() {
return new CustomProjectionList();
}
public static ProjectionList getNewCustomProjectionList() {
return new CustomProjectionList();
}
#Override
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < getLength(); i++) {
Projection proj = getProjection(i);
String sqlString = proj.toSqlString(criteria, loc, criteriaQuery);
buf.append(sqlString);
loc += getColumnAliases(loc, criteria, criteriaQuery, proj).length;
if (i < (getLength() - 1) && sqlString != null && sqlString.length() > 0)
buf.append(", ");
}
return buf.toString();
}
private static String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
projection.getColumnAliases( loc );
}
}
public class CustomPropertyProjection extends SimpleProjection {
private static final long serialVersionUID = -5206671448535977079L;
private String propertyName;
private boolean grouped;
#Override
public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return new String[0];
}
#Override
public String[] getColumnAliases(int loc) {
return new String[0];
}
#Override
public int getColumnCount(Criteria criteria, CriteriaQuery criteriaQuery) {
return 0;
}
#Override
public String[] getAliases() {
return new String[0];
}
public CustomPropertyProjection(String prop, boolean grouped) {
this.propertyName = prop;
this.grouped = grouped;
}
protected CustomPropertyProjection(String prop) {
this(prop, false);
}
public String getPropertyName() {
return propertyName;
}
public String toString() {
return propertyName;
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return new Type[0];
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
return "";
}
public boolean isGrouped() {
return grouped;
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
if (!grouped) {
return super.toGroupSqlString(criteria, criteriaQuery);
}
else {
return StringHelper.join( ", ", criteriaQuery.getColumns( propertyName, criteria ) );
}
}
}
public class CustomRowCountProjection extends SimpleProjection {
/**
*
*/
private static final long serialVersionUID = -7886296860233977609L;
#SuppressWarnings("rawtypes")
private static List ARGS = java.util.Collections.singletonList( "*" );
public CustomRowCountProjection() {
super();
}
public String toString() {
return "count(count(*))";
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] {
getFunction( criteriaQuery ).getReturnType( null, criteriaQuery.getFactory() )
};
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
SQLFunction countSql = getFunction( criteriaQuery );
String sqlString = countSql.toString() + "(" + countSql.render( null, ARGS, criteriaQuery.getFactory() ) + ") as y" + position + '_';
return sqlString;
}
protected SQLFunction getFunction(CriteriaQuery criteriaQuery) {
SQLFunction function = criteriaQuery.getFactory()
.getSqlFunctionRegistry()
.findSQLFunction( "count" );
if ( function == null ) {
throw new HibernateException( "Unable to locate count function mapping" );
}
return function;
}
}
Hope this help.

Jackson : Conditional select the fields

I have a scenario where i need to use the payload as
{"authType":"PDS"}
or
{"authType":"xyz","authType2":"abc",}
or
{"authType":"xyz","authType2":"abc","authType3":"123"}
or
any combination except for null values.
referring to the code i have 3 fields but only not null value fields be used.
Basically i don't want to include the field which has null value.
Are there any annotations to be used to get it done
public class AuthJSONRequest {
private String authType;
private String authType2;
private String authType3;
public String getAuthType() {
return authType;
}
public void setAuthType(String authType) {
this.authType = authType;
}
public String getAuthType2() {
return authType2;
}
public void setAuthType2(String authType2) {
this.authType2 = authType2;
}
public String getAuthType3() {
return authType3;
}
public void setAuthType3(String authType3) {
this.authType3 = authType3;
}
}
Try JSON Views? See this or this. Or for more filtering features, see this blog entry (Json Filters for example).
This is exactly what the annotation #JsonInclude in Jackson2 and #JsonSerialize in Jackson are meant for.
If you want a property to show up only when it is not equal to null, add #JsonInclude(Include.NON_NULL) resp. #JsonSerialize(include=Include.NON_NULL).