I'm working on a simple spring boot project.
I have this Dto class called TaskDto:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class TaskDto {
private int releveBancaireId;
private String variableName;
private String variableTypeName;
private String proccessesName;
private String id;
private String assignee;
private String name;
private String description;
private int priority;
private String processDefinitionId;
private String processInstanceId;
private Date createTime;
}
I also have a service which loops over something called Tasks, collects the data and sets it into TaskDto.
List<Task> taskList = taskService.createTaskQuery().taskAssignee(assignee).list();
String finalVariableName = variableName;
String finalVariableTypeName = variableTypeName;
return taskList.stream().map(task -> {
TaskDto taskDto = new TaskDto();
String releveBancaireIdInsideForLoop = null;
for (Task taskLoop: tasks) {
Map<String, Object> variables = taskLoop.getProcessVariables();
for (Entry<String, Object> stringObjectEntry: variables.entrySet()) {
releveBancaireIdInsideForLoop = stringObjectEntry.getValue().toString();
System.out.println("displaying releveBancaireIdInsideForLoop " + releveBancaireIdInsideForLoop);
taskDto.setReleveBancaireId(Integer.parseInt(releveBancaireIdInsideForLoop));
taskDto.setVariableName(finalVariableName);
taskDto.setVariableTypeName(finalVariableTypeName);
taskDto.setProccessesName(processDefinition.getName());
taskDto.setId(task.getId());
taskDto.setAssignee(task.getAssignee());
taskDto.setName(task.getName());
taskDto.setDescription(task.getDescription());
taskDto.setPriority(task.getPriority());
taskDto.setProcessDefinitionId(task.getProcessDefinitionId());
taskDto.setCreateTime(task.getCreateTime());
System.out.println("shwoing task dto " + taskDto);
}
}
return taskDto;
}
To simplify the issue, I have 2 Tasks. Each Task has a variable that I need, so what I'm doing is looping over them and collect the value that I want. For example, in the first loop it displays:
releveBancaireIdInsideForLoop = 1
while in the second loop shows
releveBancaireIdInsideForLoop = 2
Then, when I try to do
taskDto.setReleveBancaireId(Integer.parseInt(releveBancaireIdInsideForLoop));
It shows me on the terminal two TaskDtos with the same value (value 2 from the last loop) instead of 1 and 2. I don't know if this is the right way to set values dynamically.
Related
I am facing an issue in a springboot project,
I am trying to retrieve statistics of "Tickets" that are handled ontime using jpa specifications.
Ticket are given a number of days to handle based on the purpose.
Here is the error:
java.lang.NullPointerException: null
at com.ticketcorp.ticket.repository.TicketSpecification.lambda$isOntime$c9c337fb$1(TicketSpecification.java:208) ~[classes/:na]
Which i Believe is to be expected since i got this warning on the same line:
'Map<String, Integer>' may not contain keys of type 'Path<String>'
Here is my Ticket Entity:
#Table(name = "tickets")
public class Ticket {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String code;
private String purpose;
#Lob
#Column(columnDefinition = "TEXT")
private String content;
#Lob
#Column(columnDefinition = "TEXT")
private String solution;
#Lob
#Column(columnDefinition = "TEXT")
private String comment;
private int status;
private LocalDateTime createdAt= LocalDateTime.now();
private LocalDateTime handledAt= LocalDateTime.now();
}
Here is my Ticket Specification:
public class TicketSpecification {
public static Specification<Ticket> isOntime(ArrayList<Purpose> purposes) {
return (root, query, builder) -> {
/*Example of content for nameAndDurationMap: {Suggestion=25, Bug report=1}*/
Map<String, Integer> nameAndDurationMap = PurposeUtils.PurposeArrayToNameDurationMap(purposes);
return builder.le(
builder.diff(
builder.function("unix_timestamp", Long.class, root.get(Ticket_.handledAt)),
builder.function("unix_timestamp", Long.class, root.get(Ticket_.createdAt))
)
, nameAndDurationMap.get(root.get(Ticket_.purpose)) * 86400);/*Line 208*/
};
}
}
Here is my Ticket Service:
#Service
public class TicketService {
#Autowired
private TicketRepository ticketRepository;
public String countTicketsHandledOnTime(){
int handledStatus=2;
Specification<Ticket> allTicketHandledOnTimeQuery =where(TicketSpecification.isHandled(handledStatus)).and(TicketSpecification.isOntime(purposes));
return String.valueOf(ticketRepository.count(allTicketHandledOntimeQuery));
}
}
Here is Purpose POJO Model:
public class Purpose{
private String id;
private String name;
private String description;
private int level;
private int duration;
}
Here is PurposeUtils :
It takes a list of purposes and generate a hashmap of purpose and number of days it should take to handle a ticket of that purpose.
public class PurposeUtils {
public static Map<String, Integer> PurposeArrayToNameDurationMap(ArrayList<Purpose> purposes) {
Map<String, Integer> purposeMap = new HashMap<String, Integer>();
for(Purpose purpose: purposes) {
purposeMap.put(purpose.getName(), purpose.getDuration());
}
return purposeMap;
}
}
I assume you use javax.persistence.criteria.Root in this line:
nameAndDurationMap.get(root.get(Ticket_.purpose)) * 86400);/*Line 208*/
note documentation of Root:
Path< Y > get(String attributeName) Create a path corresponding to the
referenced attribute.
so you ask the map to get the value that indeed is not there
Note that root is not a value holder, it is a for the prdicat creation, so in your predict you will say I want value X(root) to met Y condition
this will become SQL query, so it has to be values that SQL can handle, your code will not be called on every ticket... if you want to do it either makes it iterate every purpose
(
if purpose_x == Ticket_.purpose and le(...)
or purpose_y == Ticket_.purpose and le(...)
)
or move the logic to DB function you can call
code that will give the idea but probably will not run since it dry:
public class TicketSpecification {
public static Specification<Ticket> isOntime(ArrayList<Purpose> purposes){
return (root, query, builder) -> {
List<Predicate> predicates = new ArrayList<>();
for(Purpose purpose: purposes) {
predicates.add(isOntime(purpose.getName(), purpose.getDuration(),root, query, builder);
}
return builder.or(predicates.toArray(new Predicate[0]));
}
}
public static Predicate isOntime(String purposes_name,int purposes_time,Root<Ticket> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return builder.and(
builder.equal(root.get(Ticket_.purpose),purposes_name)
,
builder.le(
builder.diff(
builder.function("unix_timestamp", Long.class, root.get(Ticket_.handledAt)),
builder.function("unix_timestamp", Long.class, root.get(Ticket_.createdAt))
)
,(purposes_time * 86400);/*Line 208*/
)
);
}
}
I have the following entity class:
public class Conversation {
private String id;
private String ownerId;
private Long creationDate;
public Conversation(String id, String ownerId, Long creationDate){
this.id = id;
this.ownerId = ownerId;
this.creationDate = creationDate;
}
}
On other submodule through an external service, on each insertion, I recive a map of the following entities:
public class AttributeValue {
private Sring s; //string attribute
private String n; //number attribute
public String getS() {
return this.s;
}
public String getN() {
return this.n;
}
public AttributeValue(String s, String n){
this.s = s;
this.n = n;
}
}
//Example if I insert this conversation: new Conversation("1", "2", 1623221757971)
// I recive this map:
Map<String, AttributeValue> insertStream = Map.ofEntries(
entry("id", new AttributeValue("1", null)),
entry("ownerId", new AttributeValue("2", null)),
entry("creationDate", new AttributeValue(null, "1623221757971"))
);
To read the ownerId field from the map, I have to do this:
String ownerId = insertStream.get("ownerId").getS();
My question is, instead of have to write: insertStream.get("ownerId"), exists any way through Reflection to read the name of the field from the entity (Conversation.ownerId)?
This is because we want to mantain the submodule and If we make a change on the entitity, for example change ownerId for ownerIdentifier, the submodule shows a compilation error or is changed automatically.
Is this what you want? Field#getName()
Example code:
Field[] conversationFields = Conversation.class.getDeclaredFields();
String field0Name = conversationFields[0].getName();
Depending on the JVM used, field0Name can be "id". You can also use Class#getFields(), this method includes all Fields that are accessible in this class (super class's fields).
Another option (not using reflection) would be to refactor your code.
import java.util.Map;
import java.util.HashMap;
public class Conversation {
public static String[] names = {
"id", "ownerId", "creationDate"
};
private Map<String, Object> data = new HashMap<String,Object>();
public Conversation(Object... data) {
if(data.length!=names.length)
throw new IllegalArgumentException("You need to pass "+names.length+" arguments!");
for(int i=0; i<names.length; i++)
data.put(names[i],data[i]);
}
public Map<String,Object> getData() { return data; }
// You can pass "id"/"ownerId" or names[0]/names[1]
public String getString(String key) {
return (String)data.get(key);
}
// You can pass "creationDate" or names[2]
public long getLong(String key) {
return (long)data.get(key);
}
}
You could then create Conversation Objects like before:
Conversation c = new Conversation("myId","myOwnerId",123456789L);
You could also add public static String fields like ID="id", but changing the value of a field will never change the field's name.
I started using Project Reactor recently and I can't work out how to work with nested streams. I want to update data of outer Mono with some data of inner Mono.
#GetMapping("/search")
public Mono<Github> combineGithubData() {
WebClient client = WebClient.create("https://api.github.com");
Mono<Github> data = client.get().uri(URI.create("https://api.github.com/users/autocorrectoff")).retrieve().bodyToMono(Github.class);
data = data.map(s -> {
client.get().uri(URI.create("https://api.github.com/users/Kukilej")).retrieve().bodyToMono(Github.class).map(m -> {
s.setXXX(m.getName());
return m;
});
return s;
});
return data;
}
The field XXX is always returned as null, although I have set it to a value from inner Mono. I'm pretty sure this would work in RxJs. How do I make this work with Project Reactor?
edit:
the code of the Github class
import lombok.*;
#Getter #Setter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class Github {
private String login;
private int id;
private String node_id;
private String avatar_url;
private String gravatar_id;
private String url;
private String html_url;
private String followers_url;
private String following_url;
private String gists_url;
private String starred_url;
private String subscriptions_url;
private String organizations_url;
private String repos_url;
private String events_url;
private String received_events_url;
private String type;
private boolean site_admin;
private String name;
private String company;
private String blog;
private String location;
private String email;
private String hireable;
private String bio;
private int public_repos;
private int public_gists;
private int followers;
private int following;
private String created_at;
private String updated_at;
private String XXX;
}
Your inner stream is not getting subscribed to. Either us flatMap, or better yet, use zip:
data
.zipWith(client.get().uri(...).retrieve().bodyToMono(Github.class))
.map(tuple2 -> {
//update tuple2.getT1() with m.getName() and return the updated tuple
return tuple2.mapT1(tuple2.getT1().setXXX(tuple2.getT2().getName()));
})
.map(tuple2 -> tuple2.getT1() //updated s);
zipWith() subscribes to the inner stream.
I have 3 objects List and i would like to combine it base on they unique key into one object List.
Since Loan depend on Account and Account depend on Bank
is there simple way without multiple looping for each object in java 8?
I know its better to do it in single query but wonder if there is something existing with Java 8 using List and combine it into one list.
public class Bank {
private String institution; //pk
private String transit; //pk
private String bankName;
}
public class Account {
private String institution; //pk
private String transit; //pk
private String accountNo; //pk
private String nameAccount;
}
public class Loan {
private String institution;//pk
private String transit;//pk
private String accountNo;//pk
private String serviceNo;//pk
}
// fusion object
public class CombineObject {
private String institution;
private String transit;
private String accountNo;
private String serviceNo;
private String nameAccount;
private String bankName;
}
List<Bank> lstBank = myListBank();
List<Account> lstAccount = myListAccount();
List<Loan> lstLoan = myListLoan();
I am developing an application using GeoModel. I need to perform search in a particular radius based on the given latitude and longitude. I am able to generate the GeoCells in the datastore using Objectify, but not able to get back the results in a particular radius.
I am sharing my code below.
Entity Class
#Entity
public class NewsFeed implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Index
private Long feedID;
#Index
private String topic;
#Index
private String title;
private String description;
#Index
private Date createDate;
private String imageOrVideo;
private String imageUrl;
private String blobKey;
#Latitude
private Double latitude;
#Longitude
private Double longitude;
#Geocells
private List<String> cells;
// getter and setters ...
}
Custom GeocellQueryEngine Class From This Source
public class ObjectifyGeocellQueryEngine implements GeocellQueryEngine {
private String geocellsProperty;
private Objectify ofy;
public static final String DEFAULT_GEOCELLS_PROPERTY = "cells";
public ObjectifyGeocellQueryEngine(Objectify ofy) {
this(ofy, DEFAULT_GEOCELLS_PROPERTY);
}
public ObjectifyGeocellQueryEngine(Objectify ofy, String geocellsProperty) {
this.ofy = ofy;
this.geocellsProperty = geocellsProperty;
}
#Override
public <T> List<T> query(GeocellQuery baseQuery, List<String> geocells, Class<T> entityClass) {
StringTokenizer st;
int tokenNo = 0;
Query<T> query = ofy.query(entityClass);
if (baseQuery != null) {
st = new StringTokenizer(baseQuery.getBaseQuery(), ",");
while (st.hasMoreTokens()) {
query.filter(st.nextToken(), baseQuery.getParameters().get(tokenNo++));
}
}
return query.filter(geocellsProperty + " IN", geocells).list();
}
}
Fetching Data Here
Point p = new Point(24.8993714, 79.5839124);
// Generates the list of GeoCells
List<String> cells = GeocellManager.generateGeoCell(p);
List<Object> params = new ArrayList<Object>();
params.add("Movies");
GeocellQuery baseQuery = new GeocellQuery("topic == topic", "String topic",params);
ObjectifyGeocellQueryEngine objectifyGeocellQueryEngine = new ObjectifyGeocellQueryEngine(ofy(), "cells");
List<NewsFeed> list = objectifyGeocellQueryEngine.query(baseQuery, cells, NewsFeed.class);
List<NewsFeed> list2 = GeocellManager.proximitySearch(p, 10, 10000,NewsFeed.class, baseQuery, objectifyGeocellQueryEngine, GeocellManager.MAX_GEOCELL_RESOLUTION);
System.out.println(list+" : "+list2);
Now the problem is I am not getting any results out from here. Can you people please help me with this as I am not getting any exception, just getting the empty list.
I have done a workaround for this situation I have added a parallel JDO Class to store and retrieve the geospatial results.