My project use a simple-spring-memcache to caching a service method, but it does't work, as follows:
#ReadThroughSingleCache(namespace = "AdvServiceImpl.findByIdList", expiration = 60)
public List<Adv> findByIdList(#ParameterValueKeyProvider(order = 0) List<String> idList, #ParameterValueKeyProvider(order = 1) String deviceType, #ParameterValueKeyProvider(order = 2) String sourceId) throws Exception {
But I write so it can work:
#ReadThroughSingleCache(namespace = "AdvServiceImpl.findByIdList", expiration = 60)
public List<Adv> findByIdList(List<String> idList, #ParameterValueKeyProvider(order = 0) String deviceType, #ParameterValueKeyProvider(order = 1) String sourceId) throws Exception {
#ReadThroughSingleCache shouldn't be used if one of the method's arguments annotated with ParameterValueKeyProvider is of type List. Instead of #ReadThroughSingleCache try to use #ReadThroughMultiCache
Related
This question already has answers here:
Java List<string> not adding to list after Arrays.asList() has been used
(3 answers)
Closed 4 months ago.
My controller class:
#PostMapping(value = "/uniqueUrl")
#ResponseBody
public ResponseEntity<MyResponse> urlGenerator(#RequestBody MyRequest myRequest){
log.info("Request for url : ", myRequest);
MyResponse myResponse= this.generateUrlService.urlGenerator(myRequest);
log.info("generateUniqueUrl response: ", myResponse.getLongUniqueUrlList());
return ResponseEntity.accepted().body(myResponse);
}
MyRequest class:
#Data
public class MyRequestimplements Serializable {
#NotNull(message = "Url cannot be null or empty")
private String url;
#NotNull(message = "count cannot be null or empty")
private int cound;
}
My service implemantation :
#Override
public myResponse urlGenerator(MyRequest myRequest) {
log.info("urlGenerator started..");
myUrlRequestValidator.validate(myRequest);
String longUrl = myRequest.getUrl();
int count = myRequest.getCount();
List<String> uniqueUrlList = Arrays.asList(new String[count]);
for (String string : uniqueUrlList) {
string = longUrl + "/?";
for (int i = 0; i < rand.nextInt(11)+4; i++) {
string += letters.get(rand.nextInt(35));
}
uniqueUrlList.add(string);
log.info(string);
}
MyResponse response = new MyResponse();
response.setLongUniqueUrlList(uniqueUrlList);
return response;
}
MyResponse class:
#Data
public class MyResponse extends BaseResponse {
private List<String> longUniqueUrlList;
private List<String> shortUrlList;
}
In the method where my Controller and Service class is as follows, the result of uniqueUrlList returns null. I want to add each string formed by the add method to the list, but it does not add it. Can you help me where am I going wrong?
edit1 : When I change the random url generation and adding to the list in this way, it does not enter the for loop, or when I do not change the loop and only define it as an arraylist, it gives a Null error in the add method. How can I solve this? It's such an easy thing, but I don't understand why I can't do it?
List<String> uniqueUrlList = new ArrayList<String>();
String string = null;
for ( int j = 0; j < count; j++) {
string = longUrl + "/?";
for (int i = 0; i < rand.nextInt(11)+4; i++) {
string += letters.get(rand.nextInt(35));
}
uniqueUrlList.add(string);
log.info(string);
}
}
It is null because your List<String> uniqueUrlList is initialized with Arrays.asList which are fixed in size and unmodifiable, as specified in the Javadoc. The Arrays.asList(new String[count]) is also empty as there are no elements inside the new String[count].
Instead you should initialize it with a new ArrayList<String>():
List<String> uniqueUrlList = new ArrayList<String>();
Where you can then modify the list as you please, using a loop to add to your uniqueUrlList as many as myRequest.getCount() times.
You should initialize a list by
List<String> uniqueUrlList = new ArrayList<>();
i'm totally new to java 8 streams. just want know how to write the below code using java stream api. Not sure on how to write nested loops with filters to map the data.
public AccountByCustomerDto getAccountDetails(int customerId, HttpServletRequest request) throws Exception {
List<Accountowner> accountOwnerList = repo.getAccountOwners(customerId);
List<AccountByCustomerDto.AccountDto> aDtoList = new ArrayList<AccountByCustomerDto.AccountDto>();
for (Accountowner accountOwner : accountOwnerList) {
String currency = accountOwner.getAccount1().getAccountCurrency();
if(accountOwner != null && currency.startsWith("USD")) {
List<Accountbalance> accountBalanceList = accountOwner.getAccount1().getAccountbalances();
List<AccountByCustomerDto.BalancesDto> balanceDtoList = new ArrayList<AccountByCustomerDto.BalancesDto>();
for (Accountbalance balance : accountBalanceList) {
String creditInclude = balance.getCreditLimitIncluded();
if(balance != null && creditInclude.equals("Y")) {
AccountByCustomerDto.BalancesDto balanceDto = AccountByCustomerDto.BalancesDto.builder()
.balanceType(balance.getBalanceType()).baDto(null)
.referenceDate(
balance.getReferenceDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
.build();
balanceDtoList.add(balanceDto);
}
}
String accountId = Integer.toString(accountOwner.getAccount1().getAccountId()) + ":"
+ accountOwner.getAccount1().getAccountCurrency();
AccountByCustomerDto.AccountDto adto = AccountByCustomerDto.AccountDto.builder()
.accountId(Utility.encrypt(accountId))
.accountNumberDisplay(accountOwner.getAccount1().getAccountDisplay())
.balances(balanceDtoList).accountLink(null).build();
aDtoList.add(adto);
}
}
return AccountByCustomerDto.builder().accounts(aDtoList).build();
}
I think just switching the code to Stream would make the code even less readable. So when one method gets very long it's a good idea to split it into smaller methods.
When the code is split up into smaller methods streams provide a real benefit when it comes to readability compared to traditional loops.
Element in stream remains in stream if accountOwnerCurrencyIsUSD is true. The remaining elements are mapped to a AccountDto using createAccountDto and the result is collected into a AccountDto list. Is much easier to read than create list, loop through other list, get currency, check currency, create another list...
public AccountByCustomerDto getAccountDetails(int customerId, HttpServletRequest request) throws Exception {
List<AccountByCustomerDto.AccountDto> aDtoList = accountOwnerList.stream()
.filter(this::accountOwnerCurrencyIsUSD)
.map(this::createAccountDto)
.collect(Collectors.toList());
return AccountByCustomerDto.builder().accounts(aDtoList).build();
}
private AccountCustomerDto.AccountDto createAccountDto(Accountowner owner) {
String accountId = accountOwner.getAccount1().getAccountId() + ":" + accountOwner.getAccount1().getAccountCurrency();
List<AccountByCustomerDto.BalancesDto> balanceDtoList = accountOwner.getAccount1().getAccountbalances()
.stream()
.filter(this::includesCredit)
.map(this::createBalanceDto)
.collect(Collectors.toList());
return AccountByCustomerDto.AccountDto.builder()
.accountId(Utility.encrypt(accountId))
.accountNumberDisplay(accountOwner.getAccount1().getAccountDisplay())
.balances(balanceDtoList)
.accountLink(null)
.build();
}
private AccountByCustomerDto.BalancesDto createBalanceDto(Accountbalance balance) {
return AccountByCustomerDto.BalancesDto.builder()
.balanceType(balance.getBalanceType())
.baDto(null)
.referenceDate(alance.getReferenceDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
.build();
}
private boolean accountOwnerCurrencyIsUSD(Accountowner owner) {
return accountOwner != null && "USD".eqauls(accountOwner.getAccount1().getAccountCurrency());
}
private boolean includesCredit(Accountbalance balance) {
return balance != null && "Y".equals(balance.getCreditLimitIncluded());
}
I have not way to test the code, so take it with a grain of salt.
I have built a Rally dependency, which auto creates test case, folder in Test Plan. While creating test case it checks first if there any any existing test case with same name, else it creates new test case.
This was working while total test case size was small, while the test case size increased, i am seeing duplicate test cases are created. So I made thread to wait for few seconds (Thread.sleep(8000)) after checking existing scenarios and then creating new scenario. It works by this way.
Is there better way to handle & implement this to handle any size of test case. Please advice.
String tcName = rallyMethods.getTestScenarios(parentFolder, scenarioName);
Thread.sleep(8000);
if (tcName == null) {
rallyMethods.createTestCase(parentFolder, scenarioName);
Thread.sleep(8000);
} else {
rallyMethods.updateTestCase(parentFolder, scenarioName);
Thread.sleep(8000);
}
public String getTestScenarios(String parentFolderName, String ScenarioName) throws Throwable {
String sName = null;
String pFolder;
QueryRequest testCaseRequest = new QueryRequest("TestCase");
testCaseRequest.setLimit(Integer.MAX_VALUE);
testCaseRequest.setPageSize(Integer.MAX_VALUE);
testCaseRequest.setFetch(new Fetch("FormattedID", "Name", "Workspace", "Project", "TestFolder"));
testCaseRequest.setQueryFilter(new QueryFilter("Name", "=", ScenarioName));
testCaseRequest.setWorkspace(WORKSPACE_ID);
testCaseRequest.setProject(PROJECT_ID);
QueryResponse testCaseQueryResponse = query(testCaseRequest);
int testCaseCount = testCaseQueryResponse.getTotalResultCount();
// System.out.println("TestCaseCount:" + testCaseCount);
for (int i = 0; i < testCaseCount; i++) {
JsonObject scenarioObj = testCaseQueryResponse.getResults().get(i).getAsJsonObject();
String scenarioName = String.valueOf(scenarioObj.get("Name").getAsString());
JsonElement pFolderObj = scenarioObj.get("TestFolder");
if (!(pFolderObj.isJsonNull())) {
JsonObject tFolderObj = scenarioObj.get("TestFolder").getAsJsonObject();
pFolder = String.valueOf(tFolderObj.get("Name").getAsString());
if (parentFolderName.equalsIgnoreCase(pFolder)) {
sName = scenarioName;
logger.info("Test Scenarios identified in Rally: " + sName);
} else {
logger.info("Scenario, " + ScenarioName + " not found, New Scenario will be created in Rally");
}
}
}
return sName;
}
public void createTestCase(String parentFolderName, String testCaseName) throws Throwable {
String tcName = null;
String userID = readUser();
// Query Child Folders:
QueryRequest testFolderRequest = new QueryRequest("TestFolder");
testFolderRequest.setFetch(new Fetch("Name", "Workspace", "Project"));
testFolderRequest.setQueryFilter(new QueryFilter("Name", "=", parentFolderName));
testFolderRequest.setWorkspace(WORKSPACE_ID);
testFolderRequest.setProject(PROJECT_ID);
QueryResponse testFolderQueryResponse = query(testFolderRequest);
int folderCount = testFolderQueryResponse.getTotalResultCount();
for (int i = 0; i < folderCount; i++) {
String testFolderRef = testFolderQueryResponse.getResults().get(i).getAsJsonObject().get("_ref").getAsString();
JsonObject testFolderObj = testFolderQueryResponse.getResults().get(i).getAsJsonObject();
String pFolder = String.valueOf(testFolderObj.get("Name").getAsString());
if (pFolder.equalsIgnoreCase(parentFolderName)) {
//System.out.println("Creating a test case...");
JsonObject newTC = new JsonObject();
newTC.addProperty("Name", testCaseName);
newTC.addProperty("Workspace", WORKSPACE_ID);
newTC.addProperty("Project", PROJECT_ID);
newTC.addProperty("Description", "Selenium Automated TestCase");
newTC.addProperty("TestFolder", testFolderRef);
newTC.addProperty("Method", "Automated");
newTC.addProperty("Type", "Functional");
if (!(userID == null)) {
newTC.addProperty("Owner", userID);
}
CreateRequest createRequest = new CreateRequest("testcase", newTC);
CreateResponse createResponse = create(createRequest);
if (createResponse.wasSuccessful()) {
JsonObject tcObj = createResponse.getObject();
tcName = String.valueOf(tcObj.get("Name").getAsString());
logger.info("Created test scenario name is: " + tcName);
} else {
String[] createErrors;
createErrors = createResponse.getErrors();
logger.info("Error while creating test scenario below parent folder!");
for (int j = 0; j < createErrors.length; j++) {
System.out.println(createErrors[j]);
logger.info(createErrors[j]);
}
}
}
}
}
Hmmm... I'm not too familiar with the Java REST toolkit, but I can't think of a reason why a larger set of test cases in the workspace would cause the query to fail like that.
Did you try checking testCaseQueryResponse.wasSuccessful()? If it returns false, can you see what the error is? testCaseQueryResponse.getErrors()
My first thoughts are that you should provide a reasonable value for the limit and pageSize parameters, rather than passing Integer.MAX_VALUE. And second, rather than checking if the returned test cases are in the specified parent folder, you should include a query filter to filter the test cases results on TestFolder.Name = parentFolderName. Then you should only be expecting either 1 or 0 results returned (assuming that you're expecting all test cases within a test folder to have unique names).
Is there a method can convert & delimited String to a java class?
Foo foo = Foo.fromString("name1=a&name2=b");
I am coding the twitter api: https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token. the response is
I need need a function do the blow things for me.
String respnse = "oauth_token=6253282-eWudHldSbIaelX7swmsiHImEL4KinwaGloHANdrY&oauth_token_secret=2EEfA6BG3ly3sR3RjE0IBSnlQu4ZrUzPiYKmrkVU&user_id=6253282&screen_name=twitterapi";
String [] resParas = respnse.split("&");
for(String respara : resParas){
if(respara.indexOf("oauth_token=")>=0){
int index = "oauth_token=".length();
access_token = respara.substring(index);
}else if(respara.indexOf("oauth_token_secret=")>=0){
int index = "oauth_token_secret=".length();
access_token_secret = respara.substring(index);
}else if(respara.indexOf("user_id=")>=0){
int index = "user_id=".length();
user_id = respara.substring(index);
}else if(respara.indexOf("screen_name=")>=0){
int index = "screen_name=".length();
screen_name = respara.substring(index);
}
}
You can use UriComponentsBuilder for this:
MultiValueMap<String, String> parameters = UriComponentsBuilder
.fromUriString("http://twitter.com/oauth?oauth_token=6253282-eWudHldSbIaelX7swmsiHImEL4KinwaGloHANdrY&oauth_token_secret=2EEfA6BG3ly3sR3RjE0IBSnlQu4ZrUzPiYKmrkVU&user_id=6253282&screen_name=twitterapi")
.build()
.getQueryParams();
Will give you a map with all params:
{oauth_token=[6253282-eWudHldSbIaelX7swmsiHImEL4KinwaGloHANdrY], oauth_token_secret=[2EEfA6BG3ly3sR3RjE0IBSnlQu4ZrUzPiYKmrkVU], user_id=[6253282], screen_name=[twitterapi]}
I need to add some or clauses to query. I need to do it in a loop.
StringTokenizer st = new StringTokenizer(symptoms, ",");
while(st.hasMoreTokens()){
qb.whereOr(Properties.Symptom.like("%" + st.nextToken() + "%"));
}
How I can add those or conditions properly, because this above is not working as expected. I want to add or for every symptom.
If you look at the documentation, you'll see that whereOr() takes an unbounded number of conditions. What you want to do is add them all at once in an array:
StringTokenizer st = new StringTokenizer(symptoms, ",");
ArrayList<WhereCondition> whereConditions = new ArrayList<WhereCondition>();
while(st.hasMoreTokens()){
whereConditions.add(Properties.Symptom.like("%" + st.nextToken() + "%"));
}
// Give the ArrayList an already allocated array to place its contents in.
WhereCondition[] conditionsArray = new WhereCondition[whereConditions.size()];
conditionsArray = whereConditions.toArray(conditionsArray);
qb.whereOr(conditionsArray);
It looks like the method call in the documentation takes two non-array WhereConditions and then an ellipsized argument, which accepts an array or an additional comma-separated list of objects. So you might have to do something like this to get it to work properly:
qb.whereOr(conditionsArray[0], conditionsArray[1], Arrays.copyOfRange(conditionsArray, 2, conditionsArray.length));
ADDENDUM: It looks like you're using APIs that don't match the documentation, possibly an older version of greenDAO. I wrote this solution based off the current documentation. I can't guarantee that it will work for you. I recommend updating if possible.
Try this:
StringTokenizer st = new StringTokenizer(symptoms, ",");
WhereCondition where = null;
while(st.hasMoreTokens()){
if (where != null) {
where = qb.or(where, Properties.Symptom.like("%" + st.nextToken() + "%"));
} else {
where = Properties.Symptom.like("%" + st.nextToken() + "%");
}
}
qb.where(where).list();
I had the same problem so I added my own method in an Util class to perform the same behavior when I have one or several WhereCondition in an array.
Here is my gateway method :
public static QueryBuilder whereOr(QueryBuilder queryBuilder, WhereCondition[] whereConditions){
if(whereConditions == null) return queryBuilder.where(null);
else if(whereConditions.length == 1) return queryBuilder.where(whereConditions[0]);
else return queryBuilder.whereOr(whereConditions[0], whereConditions[1], Arrays.copyOfRange(whereConditions, 2, whereConditions.length));
}
Use : Util.whereOr(queryBuilder, whereConditionsArray);
Default : Can't use the Builder Pattern from the QueryBuilder with this approach
(More later) Here, I share you some code which could spare you time when developping DAO methods.
public class QueryBuilderUtil {
public static final String EQ = "=?";
public static final String NOTEQ = "<>?";
public static final String LIKE = " LIKE ?";
public static final String GE = ">=?";
public static final String LE = "<=?";
public static final String GT = ">?";
public static final String LT = "<?";
public static QueryBuilder whereOrOnSamePropertyWithDifferentValues(QueryBuilder queryBuilder, Property property, String operation, String values, String separator) {
return whereOrOnSamePropertyWithDifferentValues(queryBuilder, property, operation, values.split(separator));
}
public static QueryBuilder whereOrOnSamePropertyWithDifferentValues(QueryBuilder queryBuilder, Property property, String operation, String[] values) {
WhereCondition[] whereConditions = new WhereCondition[values.length];
int i = 0;
for (String value : values) {
whereConditions[i++] = new WhereCondition.PropertyCondition(property, operation, value);
}
return whereOr(queryBuilder, whereConditions);
}
public static QueryBuilder whereOr(QueryBuilder queryBuilder, WhereCondition[] whereConditions) {
if (whereConditions == null) return queryBuilder.where(null);
else if (whereConditions.length == 1) return queryBuilder.where(whereConditions[0]);
else return queryBuilder.whereOr(whereConditions[0], whereConditions[1], Arrays.copyOfRange(whereConditions, 2, whereConditions.length));
}
}
With this class, you can perform a whereOr with the same property on multiples "values string" in one line. It was necessary to clean my code :). However you can only do simple operations like variables declared in the class.
Example :
public List<Block> loadAllByModId(String mods_id) {
synchronized (this) {
QueryBuilder<Block> queryBuilder = queryBuilder();
QueryBuilderUtil.whereOrOnSamePropertyWithDifferentValues(queryBuilder, Properties.ModId, QueryBuilderUtil.EQ, mods_id, ";");
query_list = queryBuilder.build();
}
Query<Block> query = query_list.forCurrentThread();
return query.list();
}
Hope it helps