Trying to implement Contract Testing using Pact.
I'm starting off with Consumer side right now. It is event-driven messages so I am using MessagePactBuilder
I will give an example of what I have and what I'm trying to achieve.
What I currently have:
#Pact
public MessagePact validMessage(MessagePactBuilder builder){
PactDslJsonBody body = new PactDslJsonBody();
body.object("student")
.stringType("studentFirstName")
.stringType("studentLastName")
.stringType("studentAddress") // I understand this won't work.
Map<String, String> metadata = new HashMap<String, String>();
metadata.put("contentType", "application/json");
return builder
.given("validMessage")
.expectsToReceive()
.withMetadata(metadata)
.withContent(body)
.toPact();
}
The issue I have is the student class is composed of
String studentFirstName
String studentLastName
Address studentAddress
So you can see that it is also taking in an Address object.
The Address object consists of all strings
String addressLine
String city
String state
String zip
Any ideas on how I can create the PactDslJsonBody this way? Or if I need to implement it another way? Any ideas would be appreciated.
You can find some examples at https://docs.pact.io/implementation_guides/jvm/consumer#examples
In your case, using the PactDslJsonBody, it would look like the following:
body
.object("student")
.stringType("studentFirstName")
.stringType("studentLastName")
.object("studentAddress")
.stringType("adressLine")
.stringType("city")
// Others...
.closeObject()
.closeObject()
(False indentation to match the JSON structure)
This can become very verbose and hard to read because of missing indentation. That's why there's an alternative syntax using LambdaDsl:
newJsonBody((o) -> {
o.object("student", (s) -> {
s.stringType("studentFirstName");
s.object("studentAddress", (a) -> {
a.stringType("adressLine");
// Others...
});
// Others...
});
})
.build();
This syntax naturally looks' like the JSON structure even though it's still quite verbose.
If you want less verbose syntax, only alternative is to use Kotlin or Scala.
Related
I'm trying to implement a friends list which needs to be stored in a .json file, in Kotlin/Java with libgdx, but this isn't neccesary(Java is fine).
My code for (1) doesn't work so instead of pasteing it here I'll just try to explain my design and only paste the one for (2) as this I believe is closer to a good implementation.
I made a "Friend" class. When adding a new friend the main thread created such an object, then I read the existing "FriendsList.json" into a string, edited the string by removing "]" and appending the serialized Friend object and a "]" to close the array.
I had and still have a feeling this isn't good, so I changed it.
I made a "FriendArray" class, in which I thought of storing "Friend" objects in an List. I think this would allow me to get rid of the string manipulation code, and just serialize the FriendList class itself, which would hopefully also be easier to read. One of the problems is that addFriendToListOfFriends() doesn't add the data in the objects (it adds "{}" instead of also inserting the name and id).
What do you think of (2) ? Do you know a better way of doing this?
(Just to be clear, I'm more interested in the design and less about compilable code)
import com.badlogic.gdx.files.FileHandle
import com.unciv.json.json (this is com.badlogic.gdx.utils.Json)
import java.io.Serializable
class FriendList() {
private val friendsListFileName = "FriendsList.json"
private val friendsListFileHandle = FileHandle(friendsListFileName)
private var friendListString = ""
var arrayOfFriends = FriendArray()
fun getFriendsListAsString(): String {
return friendsListFileHandle.readString()
}
fun addNewFriend(friendName: String, playerID: String) {
val friend = Friend(friendName, playerID)
arrayOfFriends.addFriendToListOfFriends(friendName, playerID)
saveFriendsList()
}
fun saveFriendsList(){
friendListString = getFriendsListAsString()
friendListString = friendListString.plus(json().prettyPrint(arrayOfFriends))
friendsListFileHandle.writeString(friendListString, false)
}
}
class Friend(val name: String, val userId: String)
class FriendArray(): Serializable {
var nrOfFriends = 0
var listOfFriends = listOf<Friend>()
fun addFriendToListOfFriends(friendName: String, playerID: String) {
var friend = Friend(friendName, playerID)
listOfFriends.plus(friend)
}
}
You don't realy need a class FriendArray for this. You can just searialize a list to JSON. Also it's easier to load the existing friend list to a list, add the new friend to the list and serialize the new list, instead of appending a string.
This way you won't have to worry about the correct JSON format or string manipulation. You just add an object to a list, and serialize the list.
Something like this should work (in java, sorry I don't know enough kotlin to implement this):
public void addFriendAndSerializeToFile(Friend friend) {
// load existing friend list from the file
Json json = new Json();
// here the first parameter is the List (or Collection) type and the second parameter is the type of the objects that are stored in the list
List<Friend> friendList = json.fromJson(List.class, Friend.class, friendsListFileHandle);
// add the new friend to the deserialized list
friendList.add(friend);
// serialize the whole new list to the file
String serializedFriendListWithNewFriendAdded = json.prettyPrint(friendList);
// write to the file handle
fileHandle.writeString(serializedFriendListWithNewFriendAdded, false);
}
As far as I know, Google Closure Template doesn't allow passing Java object into the template (as compared to FreeMarker). So I can't really do something like:
// Java file
class Course {
...
public function getName() {
return name;
}
}
// Main function
public static void main(String args[]) {
// Get all courses
List<Course> courses = Courses.getAllCourses();
Map<String, Object> params = new HashMap<String, Object>();
params.put("courses", courses);
String out = tofu.newRenderer("template.listCourses").setData(params);
}
// Soy file
/**
* #param courses List of courses
*/
{template .listCourses}
Courses List! <br/>
{foreach $course in $courses}
New Course: {$course.name}
{/foreach}
{/template}
I'm thinking if I want to do this I probably have to write a custom function that uses Reflection to turn Course object into a Map? I'm not experienced with Java Reflection. Is there such a function available?
In plovr, I created a utility, SoyDataUtil.java, which takes a JsonElement and converts it into a SoyData. Admittedly, you may only find this useful if you are already using Gson, but the nice thing about this approach is that Gson is likely to take care of the getter/setter reflection for you. For example, I believe you should be able to do:
JsonElement json = (new Gson()).toJsonTree(courses);
SoyData soyData = SoyDataUtil.jsonToSoyData(json);
Map<String, Object> params = new HashMap<String, Object>();
params.put("courses", soyData);
The trick is leveraging Gson to do to the reflection to turn courses into a JsonElement. Not sure whether you're willing to add these dependencies (though the code from plovr is quite small -- you can just copy it directly), but this may be the most expedient solution.
Is there any String replacement mechanism in Java, where I can pass objects with a text, and it replaces the string as it occurs?
For example, the text is:
Hello ${user.name},
Welcome to ${site.name}.
The objects I have are user and site. I want to replace the strings given inside ${} with its equivalent values from the objects. This is same as we replace objects in a velocity template.
Use StringSubstitutor from Apache Commons Text.
Dependency import
Import the Apache commons text dependency using maven as bellow:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
Example
Map<String, String> valuesMap = new HashMap<String, String>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);
Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, then inserts the formatted strings into the pattern at the appropriate places.
Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
My preferred way is String.format() because its a oneliner and doesn't require third party libraries:
String message = String.format("Hello! My name is %s, I'm %s.", name, age);
I use this regularly, e.g. in exception messages like:
throw new Exception(String.format("Unable to login with email: %s", email));
Hint: You can put in as many variables as you like because format() uses Varargs
I threw together a small test implementation of this. The basic idea is to call format and pass in the format string, and a map of objects, and the names that they have locally.
The output of the following is:
My dog is named fido, and Jane Doe owns him.
public class StringFormatter {
private static final String fieldStart = "\\$\\{";
private static final String fieldEnd = "\\}";
private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
private static final Pattern pattern = Pattern.compile(regex);
public static String format(String format, Map<String, Object> objects) {
Matcher m = pattern.matcher(format);
String result = format;
while (m.find()) {
String[] found = m.group(1).split("\\.");
Object o = objects.get(found[0]);
Field f = o.getClass().getField(found[1]);
String newVal = f.get(o).toString();
result = result.replaceFirst(regex, newVal);
}
return result;
}
static class Dog {
public String name;
public String owner;
public String gender;
}
public static void main(String[] args) {
Dog d = new Dog();
d.name = "fido";
d.owner = "Jane Doe";
d.gender = "him";
Map<String, Object> map = new HashMap<String, Object>();
map.put("d", d);
System.out.println(
StringFormatter.format(
"My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.",
map));
}
}
Note: This doesn't compile due to unhandled exceptions. But it makes the code much easier to read.
Also, I don't like that you have to construct the map yourself in the code, but I don't know how to get the names of the local variables programatically. The best way to do it, is to remember to put the object in the map as soon as you create it.
The following example produces the results that you want from your example:
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
Site site = new Site();
map.put("site", site);
site.name = "StackOverflow.com";
User user = new User();
map.put("user", user);
user.name = "jjnguy";
System.out.println(
format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}
I should also mention that I have no idea what Velocity is, so I hope this answer is relevant.
Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.
Create a map of all the objects that will be referenced in the template.
Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.
There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL
I like and have successfully used MVEL in at least one project.
Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context
Handlebars.java might be a better option in terms of a Velocity-like syntax with other server-side templating features.
http://jknack.github.io/handlebars.java/
Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));
I use GroovyShell in java to parse template with Groovy GString:
Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
I created this utility that uses vanilla Java. It combines two formats... {} and %s style from String.format.... into one method call. Please note it only replaces empty {} brackets, not {someWord}.
public class LogUtils {
public static String populate(String log, Object... objects) {
log = log.replaceAll("\\{\\}", "%s");
return String.format(log, objects);
}
public static void main(String[] args) {
System.out.println(populate("x = %s, y ={}", 5, 4));;
}
}
Since Java 15 you have the method String.formatted() (see documentation).
str.formatted(args) is the equivalent of String.format(str, args) with less ceremony.
For the example mentioned in the question, the method could be used as follows:
"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())
Good news. Java is most likely going to have string templates (probably from version 21).
See the string templates proposal (JEP 430) here.
It will be something along the lines of this:
String name = "John";
String info = STR."I am \{name}";
System.out.println(info); // I am John
P.S. Kotlin is 100% interoperable with Java. It supports cleaner string templates out of the box:
val name = "John"
val info = "I am $name"
println(info) // I am John
Combined with extension functions, you can achieve the same thing the Java template processors (e.g. STR) will do.
There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter
http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html
However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).
I write a little web API which should it make easy to create URIs. Each resource class should contain a method createURI which takes the needed parameters. This method should use a helper method, populateUriTemplate, in the background to create an URI string. populateUriTemplate needs key value pairs to populate an URI template. In another language like Scala or Python I would use named parameters, but Java doesn't support them. So the question is: How to simulate named parameters in Java?
The straight forward solution would be to create a map:
public String createUri(int id, String name){
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
params.put("name", name);
return populateUriTemplate(params);
}
But I don't like to create a map first and put each parameter to it.
Another idea is to use a static method, param, to create key value pairs:
public String createUri(int id, String name){
return populateUriTemplate(param("id", id), param("name", name));
}
Looks much better to me!
It could be refined a bit to make it more self-explanatory, even if a few more characters are needed:
public String createUri(int id, String name){
return populateUriTemplate(key("id").value(id), key("name").value(name));
}
I've also thought of the builder pattern, but this would force the user of my API to create an explicit builder for each resource class, what would be tedious without a benefit. The type of the parameter is not important, as long as a proper implemented toString method exists.
My favourite is one of the both approaches with the static methods above (param(key, value) or key(k).value(v)). Do you know a better way to simulate named parameters in this case?
For some ideas on the builder pattern, you could see this blog post by Stephan Schmidt.
You also just gave me the idea to do the following, with fluent interfaces, a Callable, and a static method:
createUri().id(5).name("dennetik").call();
Which would require createing a Callable class (CreateUri) with the static method:
public static final CreateUriFluentInterface createUri() {
return FluentInterface.of(new CreateUri(), CreateUriFluentInterface.class);
}
And a fluent interface, like this:
public interface CreateUriFluentInterface {
public CreateUriFluentInterface id(Integer id);
public CreateUriFluentInterface name(String name);
}
Which isn't that much boilerplate code, is it?
(Well, if you tone down that horribly named CreateUriFluentInterface a bit, it isn't.)
(You would probably have CreateUriFluentInterface extend Callable<String>, to be able to reroute the call to Callable#call())
populateUriTemplate("id",id, "name",name);
void populateUriTemplate(Object... nvs){
for(int i=0; i<nvs.length/2; i++)
....
}
Maybe you like this approach:
class Params {
private HashMap<String, Object> allParams = new HashMap<String,Object>();
public Params(ParamEntry...params) {
for( ParamEntry p : params ) {
allParams.put(p.name, p.value);
}
}
public getParam(String name) {
return allParams.get(name);
}
class ParamEntry {
public String name;
public Object value;
}
}
public String createUri(Params.ParamsEntry ... params){
return populateUriTemplate(new Params(params));
}
To call it use
createUri(new Param.ParamEntry("name", valueObject) );
Inside the populateUriTemplate...
just use params.get("name");
Spring MVC does exactly this. As well as being able to bind requests to specific methods in controller classes, you can bind request parameters to method parameters. You can have a look to see how it works, but basically it picks a strategy to map the right request parameter to the right method parameter.
You basically get something like:
public String createUri(#RequestParam int id, #RequestParam String name){
return populateUriTemplate(id, name);
}
This is almost silly and slightly off topic, but using Lombok's #Builder annotation takes this closer to the desired result.
Furthermore if the builder, builder method and build method names are changed to _ they almost disappear:
import static foo.Template._;
class Resource {
String createURI(String id, String name) {
return populateURITemplate(_.id(id).name(name)._());
}
String populateURITemplate(Template t ){
return t.id+"="+t.name;
}
}
#Builder(builderClassName = "_", builderMethodName = "_", buildMethodName = "_" )
class Template {
static _ _ = _();
String id;
String name;
}
Named parameters are not the way:
Named parameters do not make your code any cleaner in this case. I would argue that they make things more complex and error prone in Java because you lose type safety and you lose compiler warnings about identifiers that do not exist.
TypeSafe Immutable Fluent Builders:
I wrote an article on a UrlBuilder implementation earlier this year, it shows a type safe fluent interface that enforces order of construction for mandatory input and allows for optional parts with sane defaults as well.
Now I will be the first to admit that the approach I use is fairly verbose, but it is extremely productive once that initial price is paid. It works with dependency injection and is easily unit testable and most importantly is composable for specialization.
final URL url1 = new UrlBuilder().scheme("http").host("www.google.com").build();
System.out.println("url1 = " + url1);
final URL url2 = new UrlBuilder().scheme("https").userInfo("xkcd", "correcthorsebatterystaple").host("admin.xkcd.com").build();
System.out.println("url2 = " + url2);
Produces:
url1 = http://www.google.com
url2 = https://xkcd:correcthorsebatterystaple#admin.xkcd.com
I am addressing the verbosity of the anonymous inner class implementations of the interfaces with another approach I am experimenting with; type safe implementations of value objects from interfaces using dynamic proxies.
This will do away with the boilerplate value objects and replace them with Map<String,?> but put a dynamically generated type safe immutable Interface wrapper around them.
I encourage you to read about both of these and see how combining them gives you a better solution than named properties ever would.
When I get time to refactor my UrlBuilder with the dynamic proxies I will post another blog post about it as well.
Named Parameters via Guice
If you are dead set on named parameters then I would recommend looking at Guice #Named bindings. You still lose the compile type checks and safety but at least you get some validations from Guice.
public class RealBillingService implements BillingService {
#Inject
public RealBillingService(#Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
In Php I really often use this one:
$conn_sets = array();
$conn_sets['login'] = "aaa";
$conn_sets['pass'] = "bbb";
How to do the same in JAVA 1.6.
I tried to do this:
private method1() {
String[] mystring = new String[] {"login" => "aaa", "pass" => "bbb"};
}
But it give's me an error.
I want to make this work, because I have an error lists declarations, and it is better to identify:
throw new MyException(myerrors['failed_login_error']);
than a:
throw new MyException(myerrors[116]);
I know I can do a new class, and throw an object:
throw new MyException(ERROR_CONSTANTS.FAILED_LOGIN_ERROR);
But I prefer the first one (the same as I use in Php).
So, any ideas?
In Java, you probably want to use the Map interface, such as a HashMap.
Although, I would say that using an Enum is actually what you should be doing in your second (list of errors) example. Forget about PHP when you're in Java. Enums are much better in this case because you want a well-defined list of keys.
You really should be using Properties (or better yet a ResourceBundle to abstract the properties file) for this particular case.
Here is a tutorial on the usage.
This is a much better way as you can internationalize (I18N) the messages (if you want) and you can specify them in text files rather than inside the code (messages are much better in text than in code so you can update them without having to rebuild).
You don't want to use a HashMap or a Properties object to store wildly named parameters. You really want to think object-oriented and use a class to encapsulate the data of an account and to express what an object really represents in the real world:
String username = "aaa";
String password = "bbb";
Account acc = new Account(username,password);
if (!tryLogin(acc)) {
throw new LoginFailedException(account);
}
That way, clients who catch the LoginFailedException can make use of the information and use statically typed methods with good names to, for example, retrieve the username by calling loginFailedException.getUsername().
You could use the double brace pattern:
Map<String, String> map = new HashMap<String, String>() {{
put( "login", "aaa" );
put( "pass", "bbb" );
}};
... and your other example:
throw new MyException( myErrors.get( "failed_login_error" ) );