OCPJP 8 II Consumer vs Supplier IZ0-809 - java-8

I am trying to get IZO-809 certification I was reading the OCA/OCP SE8 test book and a code really caught my attention.
The code gets me to this question.
I know consumer get a parameter and not return nothing and Supplier has not parameters and returns a value.
But this code is almost the same after the ->.
public class Pregunta24{
private final Object obj;
public Pregunta24(final Object obj){
this.obj = obj;
}
}
//Returns a Supplier
private final Supplier<Pregunta24>supplier = ()->new Pregunta24("HI");
//Returns a Consumer.
private final Consumer<Pregunta24>consumer = a->new Pregunta24(a);
Both codes work.
But if this code not work i know that consumer doesn't return nothing.
private final Consumer<String>consumerString = String::length
I know this not work because consumer doesn't return a value my question is in the supplier code and the consumer code the code is right after the -> mark but this time is considered return in fact a instance of the class.
My question is why sometimes Java complaints that is a return value and something not?
I mean this code.
private final Supplier<Pregunta24>supplier = ()->new Pregunta24("HI");
// I would think is returning a instance of the Pregunta24 class.
private final Consumer<Pregunts24>consumer = a->new Pregunta24(a);
Is returning the same after the -> but why in the consumer don't say the error.
incompatible types: bad return type in lambda expression
But if do this I do
final Consumer<String>consumerString = a->1;
I think the code after the -> is context inferred.

According to javadoc Consumer:
Represents an operation that accepts a single input argument and
returns no result.
Consumer<Pregunts24>consumer = a->new Pregunta24(a);
doesn't actually return anything. This basically is implementation of Consumer#accept method, which accepts an object of type T and has void as return type.
public void accept(Pregunta24 a) {
new Pregunta24(a);
}
You are not returning anything. Same thing with
Consumer<String>consumerString = String::length
public void accept(String a) {
a.length();
}
However
Consumer<String>consumerString = a->1;
is an invalid expression which is translated to something like this:
public void accept(String a) {
1;
}

Related

Gson IllegalStateException: Expected an int but was BEGIN_ARRAY at line 1 column Y

Since I've added an integer to my Schedule class, Gson is throwing an error on some devices: java.lang.IllegalStateException: Expected an int but was BEGIN_ARRAY at line 1 column Y (e.g. column 112 or 120 etc). I looked at this and this answer, which seems to suggest Gson is expecting an int but is getting a BEGIN_ARRAY char, but I have no idea why this would happen after the refactor of adding an extra int to the class.
Before this, my code to parse the list of Schedule objects from a stored Json string was working perfectly fine. I added the Since annotation because of the exception being thrown. Here's the Schedule class:
public class Schedule {
/**
* Added this variable
*/
#Since(1.1) private int addedVar;
/**
* All other variables have the #Since(1.0) annotation
*/
#Since(1.0) all other vars;
}
The function to parse the schedules:
public static ArrayList<Schedule> schedulesFromJson(String schedulesJson) {
Type listType = new TypeToken<ArrayList<Schedule>>(){}.getType();
Gson gson = new Gson();
try {
return gson.fromJson(schedulesJson, listType);
} catch (Exception exception) {
// Try to use the previous version of the schedule, because of IllegalStateException
gson = new GsonBuilder().setVersion(1.0).create();
return gson.fromJson(schedulesJson, listType);
}
}
The strange thing is: on some devices (like my own test devices), this crash never happened. Because of the crash, I added the Since annotation with the try and catch clause, since I expected it might have to do with the extra integer being added and could prevent that by simply reading in the old Schedule version, but this is still throwing the same exception in the catch clause.
Any help with why this is happening?
Figured it out: Because Proguard wasn't set up to not obfuscate the Schedule object (thanks #Marcono1234 for tipping me in the right direction), the Schedule object was stored in storage as an obfuscated object ({"a":true,"b":"Name","c":[true,true,true,true,true,false,false], etc}) instead of using the variable names.
The Exception was thrown because, based on the Schedule class structure before adding the addedVar, there was an array in the schedule. Easier with example.
The old schedule class:
public class Schedule {
private boolean isActive;
private String scheduleName;
private boolean[] days;
private final long timeCreated;
private ArrayList<String> list;
}
The new schedule class:
public class Schedule {
private boolean isActive;
private String scheduleName;
private boolean[] days;
private final long timeCreated;
private int addedVar; // <-- Here it goes wrong
private ArrayList<String> list;
}
Because of adding the int variable before the ArrayList<String> list, when Gson tried to deserialize the stored JSON String, it expected to see an int (the addedVar, but instead saw BEGIN_ARRAY, from the list.
I fixed it by placing the `addedVar`` after the list in my Schedule class, so the Since(1.0) annotation will properly work.

How can I test a session method?

I'm trying to #Test a Service class but there are several get() methods that I don't know how to test. I would need to know how to collect the data that is necessary or at least how to test the rest of the methods of the TokenHelper class.
This is the Session class:
public class SessionData {
public static final String KEY = "session_data";
private Integer id;
private String email;
private String fullName;
private List<Role> role;
private Boolean tempSession;
private int permissionsMask = 0;
private String avatar;
public boolean hasAnyRole(Role... roles) {
for (Role r : roles) {
if (this.role.contains(r)) {
return true;
}
}
return false;
}
}
This is the TokenHelper class:
public class TokenHelper {
public String generate(SessionData tokenData, long expirationInHours) {
return Jwts.builder()
.claim(SessionData.KEY, tokenData)
.setIssuedAt(Date.from(Instant.now()))
.setExpiration(Date.from(Instant.now().plus(expirationInHours, ChronoUnit.HOURS)))
.signWith(SignatureAlgorithm.HS256, TextCodec.BASE64.encode(secret))
.compact();
}
public UserGoogle getTokenDataFromGoogleToken(String token) throws InvalidTokenException {
try {
int i = token.lastIndexOf('.');
String withoutSignature = token.substring(0, i + 1);
Claims claims = Jwts.parser().parseClaimsJwt(withoutSignature).getBody();
return UserGoogle.builder()
.email(claims.get(UserGoogle.KEY_EMAIL).toString())
.firstName(claims.get(UserGoogle.KEY_FIST_NAME).toString())
.lastName(claims.get(UserGoogle.KEY_LAST_NAME).toString()).build();
} catch (ExpiredJwtException | MalformedJwtException | SignatureException | IllegalArgumentException ex) {
log.error(ERROR_TOKEN, ex.toString());
throw new InvalidTokenException();
}
}
}
This is my #Test:
#Test
void googleTokenHelperTest() throws InvalidTokenException {
TokenHelper obj1 = BeanBuilder.builder(TokenHelper.class).createRandomBean();
String mailGoogle = "google#prueba.com";
String firstGoogle = "Nombre";
String lastGoogle = "Apellido";
Map<String, Object> pruebaGoogle = new HashMap<String, Object>();
List<String> info = new ArrayList<String>();
info.add(firstGoogle);
info.add(lastGoogle);
pruebaGoogle.put(mailGoogle, info);
UserGoogle expectedUser = UserGoogle.builder().email(mailGoogle).firstName(firstGoogle).lastName(lastGoogle).build();
String myTestToken = pruebaGoogle.toString();
UserGoogle actualUser = obj1.getTokenDataFromGoogleToken(myTestToken);
assertEquals(actualUser, expectedUser);
}
I have created some variables to form a user, but I need to build them with a map to generate the token with the help of the generate () method. I need to know how to join those three variables and pass them to the generate () method, and then pass the result variable to the google method to generate the new user.
Edit: After clarification by OP the topic of the question changed.
Your problem arises from a flawed Object-Orientation-Design. For example, your SessionData implicitly holds a User by having String-fields relevant to a User among fields relevant to a Session. This overlapping makes it hard to test your code, because in order to test your Token-Generation for some User data, you need a Session object, which introduces additional data and dependencies.
That is one major reason, why it's difficult for you, to get a token from your three input values.
You want to test getTokenDataFromGoogleToken(String token). First thing you need to know is, what a valid Token-String will look like.
Next, you will need to mock your Claims claims object in one of two ways:
Mockito.mock it using Mockito to return the necessary Strings when claims.get() is called.
Mockito.mock your Jwts.parser().parseClaimsJwt(withoutSignature).getBody() to return a Claims object that serves your testing purpose.
Since the signature of your token will be irrelevant to your tested method, just focus on the substring before the .-Separator, i.e. the part after . in your token string can be any string you like.
If you want to test generate(SessionData, long) you need to supply a SessionData Object and a long value. After that you assertEquals the String as necessary. However, currently your code does not imply that your get is in any way related to your generate. This is, because you just handle Strings. A better design would be to have e.g. a User, Session and Token-classes, which would also make it easier to test your application and units.
A Test for your getToken method looks like the following, you just have to replace ... with your test data.
#Test
void givenGoogleToken_whenTokenHelperGeneratesUserFromToken_UserOk() {
TokenHelper helper = new TokenHelper();
String myTestToken = ...; //
UserGoogle expectedUser = ... // generate the UserGoogle Object you expect to obtain from your TokenHelper class
UserGoogle actualUser = helper.getTokenDataFromGoogleToken(myTestToken);
assertEquals(actualUser, expectedUser);
}
Test generally follow a given-when-then structure. Given some precondition, when some action is performed, then some result is returned/behaviour observed. When implemented very formally, this is called BDD (Behaviour Driven Development), but even when not practicing BDD, tests still generally follow that pattern.
In this case, I would suggest the tests be something like:
Given some data exists in the service threaddata
when I call get
then I get back the expected value
In the scenario above, the given part probably consists of setting some data on the service, the when is invoking get and the then is asserting that it's the expected value.
And I'd encourage you to consider the various scenarios. E.g what happens if the data isn't there? what happens if it's not the class the consumer asks for? Is the map case-sensitive? etc...
Code sample for the initial instance (I'm not sure what BeanBuilder is here, so I've omitted it):
#Test
public void testCurrentThreadServiceReturnsExpectedValue() {
final String key = "TEST KEY";
final String value = "TEST VALUE";
//Initialize System Under Test
CurrentThreadService sut = new CurrentThreadService();
//Given - precondition
sut.set(key, value);
//When - retrieve value
String observedValue = sut.get(key, String.class);
//Then - value is as expected
assertEquals(value, observedValue);
}
EDIT TO ADD It's always great to see someone get into unit testing, so if you have any follow ups, please ask I'm happy to help. The confidence one derives from well tested code is a great thing for software devs.

GraphQl Java, How can I blindly return all variables associated with an object from query and question on handling sub classes

I'm new to GraphQL and I'm currently implementing a GraphQL API into an established Java code, using GraphQL-SPQR and I'm running into a couple issues when it comes extracting data from hierarchical classes.
The issues that I am running into are as follows.
Firstly I don't if there is an easy way to get all the data associated with a returned node. If there is, this would be most useful for my more complex classes.
Secondly when a method returns an abstract class, I only seem able to request the variables on the abstract class. I'm sure this should be possible I am just hitting my head against a wall.
As a simple example
public abstract class Animal {
private String name;
private int age;
// Constructor
#GraphQLQuery(name = "name")
public String getName() {
return name;
}
// Age getter
}
public class Dog extends Animal {
private String favouriteFood;
// Constructor
#GraphQLQuery(name = "favouriteFood")
public String getFavouriteFood() {
return favouriteFood;
}
}
public class Database {
#GraphQLQuery(name = "getanimal")
public Animal getAnimal(#GraphQLArgument(name = "animalname") String animalname) {
return database.get(name);
}
}
So in my first question what I am currently querying is.
"{animalname(name: \"Daisy\") {name age}}"
This works fine as expected. If you imagine the class however had 10 variables I would like to merely be able to write the equivalent of the following without having to look them up.
"{node(name: \"Daisy\") {ALL}}"
Is this possible?
In terms of my second question.
The follow query, throws an error ('Field 'favouriteFood' in type 'Animal' is undefined')
"{animalname(name: \"Bones\") {name age favouriteFood}}"
likewise (reading Inline Fragments of https://graphql.org/learn/queries/)
"{animalname(name: \"Bones\") {name age ... on Dog{favouriteFood}}}"
throws an error Unknown type Dog
This is annoying as I have a number of sub classes which could be returned and may require handling in different fashions. I think I can understand why this is occuring as GraphQL has no knowledge as to what the true class is, only the super class I have returned. However I'm wondering if there is a way to fix this.
Ultimately while I can get past both these issues by simply serialising all the data to JSON and sending it back, it kind of gets rid of the point of GraphQL and I would rather find an alternate solution.
Thank you for any response.
Apologies if these are basic questions.
Answering my own question to help anyone else who has this issue.
The abstract class needs to have #GraphQLInterface included, as shown below
#GraphQLInterface(name = "Animal ", implementationAutoDiscovery = true)
public abstract class Animal {
private String name;
private int age;
// Constructor
#GraphQLQuery(name = "name")
public String getName() {
return name;
}
// Age getter
}
The following code was found after much solution and was created by the creator of SPQR. Effectively, when setting up your schema you need to declare an interface mapping strategy. The code below can be copied wholesale with only the "nodeQuery" variable being replaced with the service you are using to containing your "#GraphQLQuery" and "#GraphQLMutation" methods.
final GraphQLSchema schema = new GraphQLSchemaGenerator()
.withInterfaceMappingStrategy(new InterfaceMappingStrategy() {
#Override
public boolean supports(final AnnotatedType interfase) {
return interfase.isAnnotationPresent(GraphQLInterface.class);
}
#Override
public Collection<AnnotatedType> getInterfaces(final AnnotatedType type) {
Class clazz = ClassUtils.getRawType(type.getType());
final Set<AnnotatedType> interfaces = new HashSet<>();
do {
final AnnotatedType currentType = GenericTypeReflector.getExactSuperType(type, clazz);
if (supports(currentType)) {
interfaces.add(currentType);
}
Arrays.stream(clazz.getInterfaces())
.map(inter -> GenericTypeReflector.getExactSuperType(type, inter))
.filter(this::supports).forEach(interfaces::add);
} while ((clazz = clazz.getSuperclass()) != Object.class && clazz != null);
return interfaces;
}
}).withOperationsFromSingleton(nodeQuery)// register the service
.generate(); // done ;)
graphQL = new GraphQL.Builder(schema).build();
As this solution took some hunting, I'm going to start a blog soon with the other solutions I've stumbled on.
With regards to having a query that just returns all results. This is not possible in GraphQL. One workaround I might write is to have a endpoint that returns JSON of the entire object and the name of the object, then I can just use ObjectMapper to convert it back.
I hope this helps other people. I'm still looking into an answer for my first question and will update this post when I find one.

Sort a list of objects based on a parameterized attribute of the object

Assuming that we have an object with the following attributes:
public class MyObject {
private String attr1;
private Integer attr2;
//...
public String getAttr1() {
return this.attr1;
}
public Integer getAttr2() {
return this.attr2;
}
}
One way of sorting a list mylist of this object, based on its attribute attr1 is:
mylist.sort(Comparator.comparing(MyObject::getAttr1));
Is it possible to use this code inside a method in a dynamic way and replace the getAttr1 part with a method that returns the getter of an attribute of the object based on its name? Something like:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(Comparator.comparing(MyObject::getGetterByAttr(attr)));
}
The MyObject::getGetterByAttr(attr) part does not compile, I wrote it just as an example to explain my idea
I tried to implement a method with the following code new PropertyDescriptor(attr, MyObject.class).getReadMethod().invoke(new MyObject()) but It's still not possible to call a method with a parameter from the comparing method
You could add a method like
public static Function<MyObject,Object> getGetterByAttr(String s) {
switch(s) {
case "attr1": return MyObject::getAttr1;
case "attr2": return MyObject::getAttr2;
}
throw new IllegalArgumentException(s);
}
to your class, but the returned function is not suitable for Comparator.comparing, as it expects a type fulfilling U extends Comparable<? super U> and while each of String and Integer is capable of fulfilling this constraint in an individual invocation, there is no way to declare a generic return type for getGetterByAttr to allow both type and be still compatible with the declaration of comparing.
An alternative would be a factory for complete Comparators.
public static Comparator<MyObject> getComparator(String s) {
switch(s) {
case "attr1": return Comparator.comparing(MyObject::getAttr1);
case "attr2": return Comparator.comparing(MyObject::getAttr2);
}
throw new IllegalArgumentException(s);
}
to be used like
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(getComparator(attr));
}
This has the advantage that it also may support properties whose type is not Comparable and requires a custom Comparator. Also, more efficient comparators for primitive types (e.g. using comparingInt) would be possible.
You may also consider using a Map instead of switch:
private static Map<String,Comparator<MyObject>> COMPARATORS;
static {
Map<String,Comparator<MyObject>> comparators=new HashMap<>();
comparators.put("attr1", Comparator.comparing(MyObject::getAttr1));
comparators.put("attr2", Comparator.comparing(MyObject::getAttr2));
COMPARATORS = Collections.unmodifiableMap(comparators);
}
public static Comparator<MyObject> getComparator(String s) {
Comparator<MyObject> comparator = COMPARATORS.get(s);
if(comparator != null) return comparator;
throw new IllegalArgumentException(s);
}
More dynamic is only possible via Reflection, but this would complicate the code, add a lot of potential error source, with only little benefit, considering that you need only to add one line of source code for adding support for another property in either of the examples above. After all, the set of defined properties gets fixed at compile time.
You could also have a single place where this comparators would be defined:
static enum MyObjectComparator {
ATTR1("attr1", Comparator.comparing(MyObject::getAttr1));
MyObjectComparator(String attrName, Comparator<MyObject> comparator) {
this.comparator = comparator;
this.attrName = attrName;
}
private final Comparator<MyObject> comparator;
private final String attrName;
private static MyObjectComparator[] allValues = MyObjectComparator.values();
public static Comparator<MyObject> findByValue(String value) {
return Arrays.stream(allValues)
.filter(x -> x.attrName.equalsIgnoreCase(value))
.map(x -> x.comparator)
.findAny()
.orElseThrow(RuntimeException::new);
}
}
And your usage would be:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(MyObjectComparator.findByValue(attr));
}

Why is MassTransit using ConstructorHandling.AllowNonPublicDefaultConstructor for message deserialization?

I'm trying to incorporate MassTransit in a project that also uses NHibernate. NHibernate requires me to have at least a default constructor with protected internal visibility.
I run into the following problem. Messages can be published without any problem, however the handlers receive the message objects with uninitialized members. After some period of debugging and inspection of the MassTransit sources I found out that this is caused by the fact that MassTransit uses the setting ConstructorHandling.AllowNonPublicDefaultConstructor during deserialization, which causes my protected internal default constructor to be called instead of the parametrized constructor. I managed to reproduce this behavior, see code below.
What's the reason behind MassTransit's use of AllowNonPublicDefaultConstructor, and is there any way to change this behavior?
class Program
{
public class TestClass
{
private readonly string _someString;
public string SomeString {
get { return _someString; }
}
public TestClass(string someString)
{
_someString = someString;
}
protected internal TestClass()
{
_someString = "uninitialized";
}
}
static void Main(string[] args)
{
var obj = new TestClass("Hello World");
var serializerSettings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
ContractResolver = new ... // MassTransit contract resolver that includes private setters
};
string serializedObject = JsonConvert.SerializeObject(obj, serializerSettings);
var deserializedObj = JsonConvert.DeserializeObject<TestClass>(serializedObject, serializerSettings);
// deserializedObj.SomeString == "uninitialized"
}
}
Messages shouldn't have any logic in them at all. Messages are contracts. Any logic in them will only end up bitting you again and again. :( We will always use a default, no parameter, constructor. If there isn't one we won't deserialize your message.
We suggest that you alway consume interfaces instead of concrete types to help enforce the removal of logic from message types. But if you really want to have this behaviour you'll need to write your own serializer.
If you want to discuss further, I suggest you join the mailing list: groups.google.com/group/masstransit-discuss.

Resources