Retrieving information about a contact with Google People API (Java) - java

I am using an example of recently released Google's People API from here. I have extended a sample a bit to display additional information about the contact such as an email address and a phone number. The code that should do the job is presented below.
public class PeopleQuickstart {
...
public static void getPersonInfo(Person person){
// Get names
List<Name> names = person.getNames();
if(names != null && names.size() > 0) {
for(Name personName: names) {
System.out.println("Name: " + personName.getDisplayName());
}
}
// Get email addresses
List<EmailAddress> emails = person.getEmailAddresses();
if(emails != null && emails.size() > 0) {
for(EmailAddress personEmail: emails) {
System.out.println("Email: " + personEmail.getValue());
}
}
// Get phone numbers
List<PhoneNumber> phones = person.getPhoneNumbers();
if(phones != null && phones.size() > 0) {
for(PhoneNumber personPhone: phones){
System.out.println("Phone number: " + personPhone.getValue());
}
}
}
public static void main(String [] args) throws IOException {
People service = getPeopleService();
// Request 120 connections.
ListConnectionsResponse response = service.people().connections()
.list("people/me")
.setPageSize(120)
.execute();
// Display information about your connections.
List<Person> connections = response.getConnections();
if (connections != null && connections.size() > 0) {
for (Person person: connections){
getPersonInfo(person);
}
} else {
System.out.println("No connections found.");
}
}
}
I am testing this program with my contact list and I can successfully obtain a list of people along with the name fields. However, I cannot get values for email addresses and phone numbers (lists are always null), although I do have these values set in my contact list (verified through Gmail->Contacts). What am I missing?

Ok, problem solved. It looks like Google's documentation is a bit misleading (well, it has just been released;)). When I try to fetch my contacts using people.connections.list (see here) there are several query parameters that can be set. However, for the requestMask parameter it is stated that "Omitting this field will include all fields" which is not the case (at least did not work for me). Therefore, one has to explicitly specify which fields to be returned in the response. The modified code is given below. I wish Google people would clarify this point a bit.
public class PeopleQuickstart {
...
public static void main(String [] args) throws IOException {
People service = getPeopleService();
// Request 120 connections.
ListConnectionsResponse response = service.people().connections()
.list("people/me")
.setPageSize(120)
// specify fields to be returned
.setRequestMaskIncludeField("person.names,person.emailAddresses,person.phoneNumbers")
.execute();
// Display information about a person.
List<Person> connections = response.getConnections();
if (connections != null && connections.size() > 0) {
for (Person person: connections){
getPersonInfo(person);
}
} else {
System.out.println("No connections found.");
}
}
}

Related

How to clean up repetitive if-statements

I'm currently investing a lot of time in cleaning up my code.
I have a lot of If statements that handles my signup form in frontend.
I have a feeling that after reading the book "Clean code". That this is just ugly, however I didn't seem to find any "amazing/incredible" cleanup format for my code below.
lets say I have 15 more if-statements then this will cause a lot of duplicates, so are there any major improvements possible?
User userByUsername = userRepo.findByUsername(user.getUsername());
User userByEmail = userRepo.findUserByEmail(user.getEmail());
if (userByUsername != null && userByEmail != null) {
throw new AccountException("Email and username already exist");
}
if (userByUsername != null) {
throw new AccountException("Username already exist");
}
if (userByEmail != null) {
throw new AccountException("Email already exist");
}
Another example with another method:
public void addConditions(ReservationDto reservationDto) {
long roomId = roomService.findRoomByRoomName(reservationDto.getRoomName()).getRoomId();
// Check for adding room: Roomcapacity for timeslote reached
// If maxCapacityAfternoon reached, then only add to afternoon possible
int roomCapacity = roomService.findRoomByRoomId(roomId).getCapacity();
boolean maxCapacityMorning = roomCapacity <= getNumberOfReservationsForRoomByDateVoormiddag(roomId, reservationDto.getDate());
boolean maxCapacityAfternoon = roomCapacity <= getNumberOfReservationsForRoomByDateNamiddag(roomId, reservationDto.getDate());
boolean isMorning = reservationDto.isMorning();
boolean isAfternoon = reservationDto.isAfternoon();
capacityConditions(reservationDto, maxCapacityMorning, maxCapacityAfternoon);
// Check: Reservation can only be made when it meets the following conditions
// - Same user
// - is active
// - Morning and date overlap
// - Afternoon and date overlap
Reservation mappedReservation = mapReservationDto(reservationDto);
int amountOfReservationsForDay = reservationRepo.existsReservationForDay(mappedReservation.getUsername(), mappedReservation.getDate());
if (isMorning && isAfternoon) {
if (amountOfReservationsForDay > 0) {
throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
}
if (reservationRepo.existsReservationForMorning(mappedReservation.getUsername(), mappedReservation.getDate()) > 0
|| reservationRepo.existsReservationForAfterNoon(mappedReservation.getUsername(), mappedReservation.getDate()) > 0
) {
throw new ServiceException(RESERVATION_MSG + "in de voor- of namiddag.");
}
}
if (isMorning && !isAfternoon) {
if (amountOfReservationsForDay > 0) {
throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
}
if (reservationRepo.existsReservationForMorning(mappedReservation.getUsername(), mappedReservation.getDate()) > 0) {
throw new ServiceException(RESERVATION_MSG + "in de voormiddag.");
}
}
if (!isMorning && isAfternoon) {
if (amountOfReservationsForDay > 0) {
throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
}
if (reservationRepo.existsReservationForAfterNoon(mappedReservation.getUsername(), mappedReservation.getDate()) > 0) {
throw new ServiceException(RESERVATION_MSG + "in de namiddag");
}
}
if (!isMorning && !isAfternoon) {
throw new ServiceException("Selecteer een tijdstip voor uw reservatie");
}
}
As you can see my project has a lot of conditions when I want to add a reservation. These are only the add conditions and don't take into account the room capacity check. Which is a long list of If's as well
You could create an enum for all the data validation exceptions that can be thrown
public enum DataValidationError {
USERNAME_EXISTS,
EMAIL_EXISTS,
...
}
public static class AccountException extends Exception {
private final List<DataValidationError> errors;
public AccountException(List<DataValidationError> errors) {
this.errors = errors;
}
public List<DataValidationError> getErrors() {
return errors;
}
}
Usage:
List<DataValidationError> errors = new ArrayList<>();
User userByUsername = userRepo.findByUsername(user.getUsername());
User userByEmail = userRepo.findUserByEmail(user.getEmail());
if (userByUsername != null) {
errors.add(DataValidationError.USERNAME_EXISTS);
}
if (userByEmail != null) {
errors.add(DataValidationError.EMAIL_EXISTS);
}
if (!errors.isEmpty()) {
throw new AccountException(errors);
}
This way you could add as many errors in the enum and keep adding them to a list and throw it only once at the end.
I am not sure if any really major improvement can be applied here. But for example since you are throwing the same type of exception you might play around your error message and throw exception only once. Like:
if(userByEmail != null || userByUsername != null){
String message = (userByEmail != null ? "Email" : "Username") + " already exist";
if(userByEmail != null && userByUsername != null){
message = "Email and username already exist";
}
throw new AccountException(message);
}
For make the code more extensible and close I would use a chain of validation for this kind of things. If you know about the SOLID principle, you have a problem of SRP and OCP. By implementing a chain of validation, you would have each node have one purpose and you could easily and more validation in the futur. After you just have to create a chain !
The thing is that validation is ONE thing, so I would too create lost of tiny function with good names, so the reader can "escape early" the reading if needed.
Here is the design patern that could help you: https://refactoring.guru/design-patterns/chain-of-responsibility
I think you repository should thow those exceptions too ! If you can't find a user throw an exception in your repository. You'll have less validation all over you code and it's easyer to read.

Error in result part of Expectations : Jmockit/Junit

My test part is the following:
#Test
//testing user report method of UserAdmin - number of users less than 10
public void testuserReport_SizeLessThan10() throws Exception
{
new Expectations() {{
dBConnection.getUsers();
times=1;
result= Arrays.asList("Abc","123");
}};
System.out.println("in less than 10");
userAdmin.runUserReport();
}
The method under test belonging to a class named userAdmin is the following:
public void runUserReport() {
try {
List<User> users = dbConn.getUsers();
System.out.println(users.size());
if (users.isEmpty()) { // empty database
System.out.println("No users in database...");
} else if (users.size() <= 10) { // detailed reporting
System.out.println("Listing all usernames:");
for (User user : users) {
System.out.println(user.getUsername());
}
} else { // summary reporting
System.out.println("Total number of users: " + users.size());
System.out.println(users.get(0).getUsername());
System.out.println(users.get(1).getUsername());
System.out.println(users.get(2).getUsername());
System.out.println(users.get(3).getUsername());
System.out.println(users.get(4).getUsername());
System.out.println((users.size() - 5) + " more...");
}
} catch (SQLException sqle) {
System.out.println("DBConnection problem at runUserReport().");
}
}
My tests runs by giving the size of users as 2 but it does not print the usernames starting with "Listing all usernames:" as defined in the method. Am i defining the result wrongly in the expectations part of the test? Please help
I am not even sure how come System.out.println(users.size()); prints the size as 2 and not the test fails.
List<User> users = dbConn.getUsers(); says that users is a List of User type while result= Arrays.asList("Abc","123"); makes result as List of String, List<String>. You are assigning List<String> to List<User> and somehow it doesn't fail at run time.
You need to prepare a List of User type and assign to result instead of what you are doing currently.

Using Twitter4j how do i get all the list of Favorited tweets by a particulate user

I want all the list of tweets which are favorited by a twitter user account.
I have done some sample code that will give me all the posts that the user posted but i want all the tweets that the user favorited.
public List getAllTweetsOfUser(Twitter twitter, String user) {
if (user != null && !user.trim().isEmpty()) {
List statuses = new ArrayList();
int pageno = 1;
while (true) {
try {
int size = statuses.size();
Paging page = new Paging(pageno++, 100);
statuses.addAll(twitter.getUserTimeline(user, page));
if (statuses.size() == size) {
break;
}
} catch (TwitterException e) {
}
}
return statuses;
} else {
return null;
}
}
Can any one help me in this..
You need to start the paging with 1, and then increment the page. However, note that you will be rate limited, if you exceed 15 requests per 15 minutes (or 15* 20 = 300 statuses per 15 minutes).
Paging paging = new Paging(1);
List<Status> list;
do{
list = twitter.getFavorites(userID, paging);
for (Status s : list) {
//do stuff with s
System.out.println(s.getText());
}
paging.setPage(paging.getPage() + 1);
}while(list.size() > 0);
One of the Twitter4J samples does exactly this.
public final class GetFavorites {
/**
* Usage: java twitter4j.examples.favorite.GetFavorites
*
* #param args message
*/
public static void main(String[] args) {
try {
Twitter twitter = new TwitterFactory().getInstance();
List<Status> statuses = twitter.getFavorites();
for (Status status : statuses) {
System.out.println("#" + status.getUser().getScreenName() + " - " + status.getText());
}
System.out.println("done.");
System.exit(0);
} catch (TwitterException te) {
te.printStackTrace();
System.out.println("Failed to get favorites: " + te.getMessage());
System.exit(-1);
}
}
}
I have tried like below..
ResponseList<Status> status = twitter.getFavorites(twitterScreenName);
It given me the favorite tweets of the user which i have passed as a parameter. But the problem here is i am able to get only 20 favorites, though the user has so many tweets.
ResponseList<Status> status = twitter.getFavorites(twitterScreenName, paging);
I tried with the paging but i am not sure how to use this paging. So i am getting the top 20 favorites using my first code. If anybody tried this then please share the info like how to get all favorites of a given user.

Customize Interactive Brokers' reqIds() and reqMktData() Java methods

I am trying to write customized code within Interactive Brokers' Java API. There are a bunch of methods that get sent to TWS via the eClientSocket object. Two examples are reqIds() and reqMktData(). These are both void methods, so they do not return anything. Instead, they 'activate' methods written within the class that invokes them (in this case, SampleFrame). These methods are also void, in that they don't return any data. Instead, code is written within these methods (nextValidId() and tickPrice() respectively) to handle the data that is sent back from TWS (trader workstation).
I am having trouble creating a modified version of the nextValidId() and tickPrice() methods because reqIds() and reqMktData() don't actually specify these method names in their own code. I therefore cannot write a method called "tickPriceBlackBox()" which is called from within reqMktData(), or from within a copy of reqMktData() called reqMktDataBlackBox(). Again, there is no specific code within reqMktData() that can be modified to call a specific tickPriceBlackBox() method. It's as if code within TWS itself is hardwired to call the tickPrice() method, making it impossible for me to create a new method for returning price information.
Can anyone explain what is going on, or how to create a solution?
Here's some code:
void onReqMktData() {//requests market data from TWS / Interactive Brokers
// run m_orderDlg
m_orderDlg.init("Mkt Data Options", true, "Market Data Options", m_mktDataOptions);
m_orderDlg.show();
if( !m_orderDlg.m_rc ) {
return;
}
m_mktDataOptions = m_orderDlg.getOptions();
// req mkt data
m_client.reqMktData( m_orderDlg.m_id, m_orderDlg.m_contract,
m_orderDlg.m_genericTicks, m_orderDlg.m_snapshotMktData, m_mktDataOptions);
}
//Here is the reqMktData() method
public synchronized void reqMktData(int tickerId, Contract contract,
String genericTickList, boolean snapshot, List mktDataOptions) {
if (!m_connected) {
error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED, "");
return;
}
if (m_serverVersion < MIN_SERVER_VER_SNAPSHOT_MKT_DATA && snapshot) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support snapshot market data requests.");
return;
}
if (m_serverVersion < MIN_SERVER_VER_UNDER_COMP) {
if (contract.m_underComp != null) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support delta-neutral orders.");
return;
}
}
if (m_serverVersion < MIN_SERVER_VER_REQ_MKT_DATA_CONID) {
if (contract.m_conId > 0) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support conId parameter.");
return;
}
}
if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) {
if (!IsEmpty(contract.m_tradingClass)) {
error(tickerId, EClientErrors.UPDATE_TWS,
" It does not support tradingClass parameter in reqMarketData.");
return;
}
}
final int VERSION = 11;
try {
// send req mkt data msg
send(REQ_MKT_DATA);
send(VERSION);
send(tickerId);
// send contract fields
if (m_serverVersion >= MIN_SERVER_VER_REQ_MKT_DATA_CONID) {
send(contract.m_conId);
}
send(contract.m_symbol);
send(contract.m_secType);
send(contract.m_expiry);
send(contract.m_strike);
send(contract.m_right);
if (m_serverVersion >= 15) {
send(contract.m_multiplier);
}
send(contract.m_exchange);
if (m_serverVersion >= 14) {
send(contract.m_primaryExch);
}
send(contract.m_currency);
if(m_serverVersion >= 2) {
send( contract.m_localSymbol);
}
if(m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) {
send( contract.m_tradingClass);
}
if(m_serverVersion >= 8 && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) {
if ( contract.m_comboLegs == null ) {
send( 0);
}
else {
send( contract.m_comboLegs.size());
ComboLeg comboLeg;
for (int i=0; i < contract.m_comboLegs.size(); i ++) {
comboLeg = contract.m_comboLegs.get(i);
send( comboLeg.m_conId);
send( comboLeg.m_ratio);
send( comboLeg.m_action);
send( comboLeg.m_exchange);
}
}
}
if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) {
if (contract.m_underComp != null) {
UnderComp underComp = contract.m_underComp;
send( true);
send( underComp.m_conId);
send( underComp.m_delta);
send( underComp.m_price);
}
else {
send( false);
}
}
if (m_serverVersion >= 31) {
/*
* Note: Even though SHORTABLE tick type supported only
* starting server version 33 it would be relatively
* expensive to expose this restriction here.
*
* Therefore we are relying on TWS doing validation.
*/
send( genericTickList);
}
if (m_serverVersion >= MIN_SERVER_VER_SNAPSHOT_MKT_DATA) {
send (snapshot);
}
// send mktDataOptions parameter
if(m_serverVersion >= MIN_SERVER_VER_LINKING) {
StringBuilder mktDataOptionsStr = new StringBuilder();
int mktDataOptionsCount = mktDataOptions == null ? 0 : mktDataOptions.size();
if( mktDataOptionsCount > 0) {
for( int i = 0; i < mktDataOptionsCount; ++i) {
TagValue tagValue = (TagValue)mktDataOptions.get(i);
mktDataOptionsStr.append( tagValue.m_tag);
mktDataOptionsStr.append( "=");
mktDataOptionsStr.append( tagValue.m_value);
mktDataOptionsStr.append( ";");
}
}
send( mktDataOptionsStr.toString());
}
}
catch( Exception e) {
error( tickerId, EClientErrors.FAIL_SEND_REQMKT, "" + e);
close();
}
}
//The key piece of this code, REQ_MKT_DATA, leads to a final int variable within the EClientSocket.java object, equal to 1. tickPrice() is not mentioned anywhere.
//This method provides stock price, but doesn't return a value. You have to put executable code within this one method. I cannot duplicate and change the name of this method (tickprice();) because none of my accessible code calls it, to my knowledge. It feels as if TWS is calling tickPrice from its end.
public void tickPrice( int tickerId, int field, double price, int canAutoExecute) {
// received price tick
String msg = EWrapperMsgGenerator.tickPrice( tickerId, field, price, canAutoExecute);
m_tickers.add( msg );
}
The tickPrice method is called from EReader which gets created in EClientSocket which knows the EWrapper implementation.
Basically you call the socket reqMktData method and it will send it to TWS. EReader will see the response on the socket as a tickPrice message and will send it to the Wrapper implementation.
If you want to handle it yourself then you do it inside the tickPrice method. It could be just as simple as passing the data to a method you define.
public void tickPrice( int tickerId, int field, double price, int canAutoExecute) {
handleTick(tickerId,field,price);
}
And then write your own handleTick method
Finally may have found an answer. I'm new to Java...these appear to be callback methods. A callback method receives information from some other source. Because the method is part of an object in OOP, the returned information (stock info in this case) is returned into the callback method. Any other code that is contained within the callback method is executed when the method is replied to.
I am still not clear on how these methods are activated if they haven't been specifically executed in the code on my machine. Does Interactive Broker's know to feed information back to this method inside my Java program? Seems logical.

How to traverse an ArrayList of Objects

I have an ArrayList of custom made Users. The list is already sorted by manager.My goal is to go through the list by manager and add each user to the body of an email depending on their expiration date.
A User is basically built like this from the database. All necessary accessors/mutators are present:
id|fName|lName|...|manager
Go through the users and notify the manager if the user is expiring:
To: Manager
Expiring in 10 days
<User>
<User>
Expiring in 30 days
<User>
StringBuilder body = new StringBuilder();
ArrayList<Users> contractors;
Date today = cal.getTime();
...
if(contractors != null && contractors.size() > 0){
for(int i = 0; i < contractors.size(); i++){
if(i+1 > contractors.size()){
//do something to avoid outOfBounds and still access last item in the list
}else{
if (contractors.get(i+1).getManager() != null){
if(manager.equals(contractors.get(i+1).getManager())){
if(today.compareTo(contractor.getExpiration()){
//build body of email
}
}
}
sendEmail(manager, body.toString());
}else{
//new manager
body.equals(""); // reset email for next run
}
}
After the email is sent I want to move on to the next set of users based on manager. My problem is that I'm having trouble with the logic behind traversing the array by manager and then resetting everytime for each new manager. I'm thinking that I need another for loop?
What's the best way to do this? thanks
Edit
When implemented this way:
I would do it something like this:
if (contractors != null) {
String currentManager = null;
for (User contractor : contractors) {
String contractorManager = contractor.getManager();
if (!contractorManager.equals(currentManager) {
// a new manager
if (currentManager != null) {
sendEmail(body.toString());
body.setLength(0);
}
currentManager = contractorManager;
}
//build body of email ...
}
// send the email for the last manager
sendEmail(body.toString());
}
Iterate the list of Users and add them to a Map keyed by manager with a Set of employees per manager. Something like,
if (contractors != null && contractors.size() > 0) {
Map<String, Set<Users>> map = new HashMap<>();
for (Users contractor : contractors) {
String manager = contractor.getManager();
if (manager == null) {
manager = contractor.getName();
}
Set<Users> employees = map.get(manager);
if (employees == null) {
employees = new HashSet<>();
map.put(manager, employees);
}
employees.add(contractor);
} // now you can iterate the keySet and then each manager's employees like
for (String manager : map.keySet()) {
Set<Users> employees = map.get(manager);
for (Users u : employees) {
// ...
}
}
}
You should go for a "foreach" loop on contractors, more info here
another example here
If they are already sorted, you can take this approach (I'm using "ManagerObject" to represent the return type of Users.getManager() - replace with the actual class name):
StringBuilder body = new StringBuilder();
ManagerObject currentManager = null;
for (Users contractor : contractors) {
if (currentManager != null && !(contractor.getManager().equals(currentManager)) {
sendEmail(body.toString());
body.equals("");
}
currentManager = contractor.getManager();
// Add stuff to the body for this contractor
}
If the call to Users.getManager() is computationally expensive for some reason, this can be rejiggered to only set the currentManager upon a change in value

Categories