I have a particular part in code where all I want to do is the below, but I am at a loss to write in a way that doesn't involve code repetition. Is there a way that I can declare a list of methods, which can be then applied to productFeatureValidationDto. My current approach is noob-ish.
public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
ApplicationException, ParseException {
ValidateProductFeatureResponse response;
response = this.validateProductFeatureA(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureB(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureA(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(MPResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureC(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(MPResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureD(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureE(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
response = this.validateProductFeatureF(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
return getResponseOnValidationSuccess(productFeatureValidationDto);
}
Thanks in advance.
if you can use spring framework.
at first you can define an interface like this.
public interface ValidateProduct{
ValidateProductFeatureResponse validate(ProductFeatureValidationDto dto);
}
Your specific verification class implements this interface and register to srpingcontext
public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
ApplicationException, ParseException {
ValidateProductFeatureResponse response;
Map<String, ValidateProduct> beansOfType = applicationContext.getBeansOfType(ValidateProduct.class);
for (ValidateProduct value : beansOfType.values()) {
response = value.validate(productFeatureValidationDto);
if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
return response;
}
}
return getResponseOnValidationSuccess(productFeatureValidationDto);
}
I would suggest following approach (schematic):
/**
* List of validation functions
*/
private final static List<Function<ProductFeatureValidationDto, ProductFeatureValidationDto>> VALIDATIONS = new LinkedList<>();
/**
* Fill validations list
*/
static {
VALIDATIONS.add((source) -> {
// test for feature A
return source;
});
VALIDATIONS.add((source) -> {
// test for feature B
return source;
});
VALIDATIONS.add((source) -> {
// test for feature C
return source;
});
}
/**
* Predicate for failure determination
*/
private final Predicate<ProductFeatureValidationDto> IS_FAILURE = (dto) ->
dto.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name());
/**
* Validation method
*/
public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(
ProductFeatureValidationDto dto
) throws ApplicationException, ParseException {
// iterate over validation functions and invoke them on dto instance
// filter stream by failed validations
// stop on first match
Optional<ProductFeatureValidationDto> dtoOptional = VALIDATIONS.stream()
.map(action -> action.apply(dto))
.filter(IS_FAILURE)
.findFirst();
// apply fuilure / success maping depending on result
return dtoOptional.isPresent()
? getResponseOnValidationFailure(dto)
: getResponseOnValidationSuccess(dto);
}
I ended up composing my solution from the answers given by #Eiden and #Alexandra Dudkina. A big shoutout to them. Below is the crux of my whole solution.
So, I have two interfaces
IProductFeature : This is a functional interface which has only one method validate. Every constraint needs to implement this.
IProductValidationService: This is a contract specifying the core methods needed to be implemented. The method validateProductFeatureAgainstAllCriteria is part of the contract.
There is a config file where all the features have been imported and organised into lists as required for different kinds of products. This list has been kept in a map with the product type as key. So this is acting like a factory which is giving a list of constraint based on a given product type.
The concrete class implementing IProductValidationService gets the list from the config and then applies all the constraints in the list to the given dto.
This way, I have separated all the concerns into separate portions.
The practical advantages to this approach are:
You can write extensive test cases and documentation for individual features.
If in the future, there is a policy change in ProductFeatureB(for e.g.),all I have to do is create a new concrete class, call it ProductFeatureBV2 and change only config file. The policy changes can be documented as part of the class javadoc. This way without changing core validation method, I can deprecate ProductFeatureB. This makes the code extremely flexible.
Thanks a lot to the community for helping me getting this right. If there are further improvements to be made here, please suggest them.
Related
Is there anyway to avoid these if conditions? because there may be different type of objects coming in.
if ("OpenOrder".equals(order.getClass().getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
}
if ("ExecutionOrder".equals(order.getClass().getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
You can use a Router pattern to do this. Simple add the computations in a Map like this:
Map<String, Function> router = new HashMap<>();
router.put("OpenOrder", (value) -> OpenOrderBuilder.createOFSMessage((OpenOrder) value));
router.put("ExecutionOrder", (value) -> ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order));
And you can route the order using the String key. Here is a "OpenOrder" example:
String result = (String) router.get("OpenOrder").apply(order);
There are many ways to do it. Which one to choose, depends on your needs and in this case in particular on how many different types of objects you will have.
I suggest looking at concepts like interfaces and inheritance and on specific design patterns.
One approach I tend to like, although still not perfect, works as follows:
interface Order {
}
interface OrderBuilder<T> {
T forType();
Object createOFSMessage(Order order);
}
class OpenOrderBuilder<OpenOrder> implements OrderBuilder {
#Override
OpenOrder forType() {
return OpenOrder.class;
}
...
}
class ExecutionOrderBuilder<ExecutionOrder> implements OrderBuilder {
#Override
ExecutionOrder forType() {
return ExecutionOrder.class;
}
...
}
class MyProcessor {
Map<Class, OrderBuilder> obs;
public void initialize() {
List<OrderBuilder> builders = new ArrayList<>();
builders.add(new OpenOrderBuilder());
builders.add(new ExecutionOrderBuilder());
obs = new HashMap<Class, OrderBuilder>();
for(OrderBuilder b : builders) {
obs.put(b.forType(), b);
}
}
public Object createOFSMessage(Order order) {
return obs.get(order.getClass()).createOFSMessage(order);
}
}
In the above example, adding a new implementation would just consist of adding an entry to the builders collection. While in the example above it's done manually, normally this is done through Dependency Injection and frameworks like spring (in which case, the initialize method may turn into a constructor with builders as an #Autowired argument).
There are of course other ways, some more simple some more complicated. The best way really depends on what you have to do and one key rule: the less code you have the better.
First one should not forget the switch-on-string:
switch (order.getClass().getSimpleName()) {
case "OpenOrder":
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
case "ExecutionOrder":
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
The code however shows inheritance being used in combination with static child class factories. Evidently a createOFSMessage is not desired in the Order base class.
Then use a non-static "builder" - a factory. Follow the strategy pattern.
If you already know the type when calling the method, this code can help you :
private String CreateOFSMessage(Class<T> classOrder) {
if ("OpenOrder".equals(classOrder.getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((classOrder) order);
}else if ("ExecutionOrder".equals(classOrder.getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((classOrder) order);
}
}
I have an #Audit annotation, it has many optional attributes, I need to enforce the use of one boolean attribute useAccount = true for certain packages.
I am trying to use archunit to accomplish this validation, that way whenever a developer commits code that breaks the rule the CI will break and inform the team.
This would break the build:
#Audit
public myMethod(...) {
...
}
This is the right way:
#Audit(useAccount = true)
public myMethod(...) {
...
}
The problem is that Archunit doesn't currently support asserting over methods. I was expecting to do something like:
methods().that().resideInAnyPackage("..controllers..", "..service..").and().areAnnotatedWith(Audit.class).should(attributeCheckCondition)
Then my custom condition attributeCheckCondition would take care of looking into the attribute value.
Is there a way of retrieving methods as we retrieve classes? Without having to write a more complicated predicate and condition?
Update
Since ArchUnit 0.10.0 it is possible to create rules for members.
methods().that()
.areDeclaredInClassesThat()
.resideInAnyPackage("..controllers..", "..service..")
.and()
.areAnnotatedWith(Audit.class)
.should(attributeCheckCondition)
See also Composing Member Rules in the User Guide.
Original Answer
Since there are currently no basic rule definitions available for methods, an intermediate step is necessary. ArchUnit has a ClassesTransformer to transform JavaClasses into a collection of other types.
ClassesTransformer<JavaMethod> methods = new AbstractClassesTransformer<JavaMethod>("methods") {
#Override
public Iterable<JavaMethod> doTransform(JavaClasses javaClasses) {
Set<JavaMethod> allMethods = new HashSet<>();
for (JavaClass javaClass : javaClasses) {
allMethods.addAll(javaClass.getMethods());
}
return allMethods;
}
};
This ClassesTransformer can then be used as a base for custom rule definitions.
ArchRule rule = ArchRuleDefinition.all(methods)
.that(owner(resideInAnyPackage("..controllers..", "..service..")))
.and(annotatedWith(Audit.class))
.should(haveAttributeValue());
rule.check(javaClasses);
See also Rules with Custom Concepts in the User Guide and this issue.
I found a way of doing it with custom predicate and condition over classes, when I did that I was not aware of Roland's response which seems to be better, as it provides a way to express the rule assertion from the methods perspective which is why I was asking for.
However I wanted to post the solution here so it can be useful for others.
DescribedPredicate<JavaClass> HAVE_A_METHOD_ANNOTATED_WITH_AUDIT =
new DescribedPredicate<JavaClass>("have a method annotated with #Audit")
{
#Override
public boolean apply(JavaClass input)
{
return input.getMethods().stream().anyMatch(method -> method.isAnnotatedWith(Audit.class));
}
};
ArchCondition<JavaClass> ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE =
new ArchCondition<JavaClass>("only set useAccount attribute to true")
{
#Override
public void check(JavaClass item, ConditionEvents events)
{
item.getMethods().stream().filter(method ->
method.isAnnotatedWith(Audit.class) && !method.getAnnotationOfType(Audit.class)
.useAccount()
)
.forEach(method -> {
String message = String.format(
"Method %s is annotated with #Audit but useAccount is not set to true",
method.getFullName());
events.add(SimpleConditionEvent.violated(method, message));
});
}
};
Then the rule is expressed as:
ArchRule ANNOTATION_RULE = classes()
.that()
.resideInAnyPackage("..controller..", "..service..")
.and(HAVE_A_METHOD_ANNOTATED_WITH_AUDIT)
.should(ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE);
Here is another custom example in addition to #raspacorp (who inspired me!).
To check #Secured(ROLE) method annotation, I've implemented the following rule:
public static class SecuredByRoleArchCondition extends ArchCondition<JavaMethod> {
private final String[] expectedRoles;
public SecuredByRoleArchCondition(String[] expectedRoles) {
super(String.format("accessed by #Secured methods with roles %s", Arrays.toString(expectedRoles)));
this.expectedRoles = expectedRoles;
}
public static SecuredByRoleArchCondition haveSecuredAnnotationWithRoles(String... expectedRoles) {
return new SecuredByRoleArchCondition(expectedRoles);
}
#Override
public void check(JavaMethod javaMethod, ConditionEvents events) {
if (!javaMethod.isAnnotatedWith(Secured.class)) {
String message = String.format("Method %s annotation #Secured(%s) is missing",
javaMethod.getFullName(), Arrays.toString(expectedRoles));
events.add(SimpleConditionEvent.violated(javaMethod, message));
return;
}
String[] annotationRoleValues = javaMethod.getAnnotationOfType(Secured.class).value();
if (!Arrays.equals(annotationRoleValues, expectedRoles)) {
String message = String.format("Method %s #Secured with %s has wrong roles, expected %s instead",
javaMethod.getFullName(), Arrays.toString(annotationRoleValues), Arrays.toString(expectedRoles));
events.add(SimpleConditionEvent.violated(javaMethod, message));
}
}
}
Here is a sample usage of this archCondition:
#ArchTest
static ArchRule admin_actions_with_post_mapping_should_be_secured_by_ADMIN_WRITE_role =
methods()
.that().areDeclaredInClassesThat().resideInAnyPackage(ADMIN_PACKAGES)
.and().areAnnotatedWith(PostMapping.class)
.should(haveSecuredAnnotationWithRoles("ADMIN_WRITE"));
I am writing endpoint unit tests and for most of those there is an external web service that should be mocked, or a couple of them.
At first, i was creating mocks within tests which was okay when an endpoint test used only one external service, the mock creation was basically one liner.
As use cases became more complex, i needed to mock couple of services and exceptions for a single endpoint test.
I have put these mocks creation behind factories that all extend single factory and used builder pattern.
Within that base factory there is an inner class which i used as a builder for MockWebServiceServer.
protected class MultiStepMockBuilder {
private List<Object> mockActions = new ArrayList<Object>();
private WebServiceGatewaySupport gatewaySupport;
protected MultiStepMockBuilder(WebServiceGatewaySupport gatewaySupport) {
this.gatewaySupport = gatewaySupport;
}
protected MultiStepMockBuilder exception(RuntimeException exception) {
mockActions.add(exception);
return this;
}
protected MultiStepMockBuilder resource(Resource resource) {
mockActions.add(resource);
return this;
}
protected MockWebServiceServer build() {
MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport);
for(Object mock: mockActions) {
if (mock instanceof RuntimeException) {
server.expect(anything()).andRespond(withException((RuntimeException)mock));
}
else if (mock instanceof Resource)
{
try
{
server.expect(anything()).andRespond(withSoapEnvelope((Resource) mock));
} catch (IOException e) {e.printStackTrace();}
}
else
throw new RuntimeException("unusuported mock action");
}
return server;
}
}
}
So i can now do something like this to create mock:
return new MultiStepMockBuilder(gatewaySupport).resource(success).exception(new WebServiceIOException("reserve timeout"))
.resource(invalidMsisdn)
.build();
The issue i have with this implementation is dependence on instanceof operator which i never use outside of equals.
Is there an alternative way to instanceof operator in this scenario ? From the questions on topic of instanceof everybody argues it should only be used within equals and therefore i have feeling that this is 'dirty' solution.
Is there an alternative to instanceof operator, within Spring or as a different design, while keeping fluent interface for mocks creation ?
I don't know Spring well enough to comment specifically on this particular area, but to me, this just seems like a design thing. Generally, when you are faced with using instanceof, it means that you need to know the type, but you don't have the type. It is generally the case that we might need to refactor in order to achieve a more cohesive design that avoids this kind of problem.
The root of where the type information is being lost, is in the List of mock actions, which are currently just being stored as a List of Objects. One way to help with this then, is to look at the type of the List and consider if there is a better type that could be stored in the List that might help us later. So we might end up with a refactoring something like this.
private List<MockAction> mockActions = new ArrayList<MockAction>();
Of course, then we have to decide what a MockAction actually is, as we've just made it up. Maybe something like this:
interface MockAction {
void performAction(MockWebServiceServer server);
}
So, we've just created this MockAction interface, and we've decided that instead of the caller performing the action - we're going to pass the server into it and ask the MockAction to perform itself. If we do this, then there will be no need for instanceof - because particular types of MockActions will know what they contain.
So, what types of MockActions do we need?
class ExceptionAction implements MockAction {
private final Exception exception;
private ExceptionAction(final Exception exception) {
this.exception = exception;
}
public void performAction(final MockWebServiceServer server) {
server.expect(anything()).andRespond(withException(exception);
}
}
class ResourceAction implements MockAction {
private final Resource resource;
private ResourceAction(final Resource resource) {
this.resource = resource;
}
public void performAction(final MockWebServiceServer server) {
/* I've left out the exception handling */
server.expect(anything()).andRespond(withSoapEnvelope(resource));
}
}
Ok, so now we've gotten to this point, there are a couple of loose ends.
We're still adding exceptions to the list of MockActions - but we need to change the add methods to make sure we put the right thing in the list. The new versions of these methods might look something like this:
protected MultiStepMockBuilder exception(RuntimeException exception) {
mockActions.add(new ExceptionAction(exception));
return this;
}
protected MultiStepMockBuilder resource(Resource resource) {
mockActions.add(new ResourceAction(resource));
return this;
}
So, now we've left our interface the same, but we're wrapping the resource or exception as they're added to the list so that we have the type specificity we need later on.
And then finally, we need to refactor our method that actually makes the calls, which now looks something like this - which is much simpler and cleaner.
protected MockWebServiceServer build() {
MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport);
for(MockAction action: mockActions) {
action.performAction(server);
}
return server;
}
I have a "legacy" code that I want to refactor.
The code basically does a remote call to a server and gets back a reply. Then according to the reply executes accordingly.
Example of skeleton of the code:
public Object processResponse(String responseType, Object response) {
if(responseType.equals(CLIENT_REGISTERED)) {
//code
//code ...
}
else if (responseType.equals(CLIENT_ABORTED)) {
//code
//code....
}
else if (responseType.equals(DATA_SPLIT)) {
//code
//code...
}
etc
The problem is that there are many-many if/else branches and the code inside each if is not trivial.
So it becomes hard to maintain.
I was wondering what is that best pattern for this?
One thought I had was to create a single object with method names the same as the responseType and then inside processResponse just using reflection call the method with the same name as the responseType.
This would clean up processResponse but it moves the code to a single object with many/many methods and I think reflection would cause performance issues.
Is there a nice design approach/pattern to clean this up?
Two approaches:
Strategy pattern http://www.dofactory.com/javascript/strategy-design-pattern
Create dictionary, where key is metadata (in your case metadata is responseType) and value is a function.
For example:
Put this in constructor
responses = new HashMap<string, SomeAbstraction>();
responses.Put(CLIENT_REGISTERED, new ImplementationForRegisteredClient());
responses.Put(CLIENT_ABORTED, new ImplementationForAbortedClient());
where ImplementationForRegisteredClient and ImplementationForAbortedClient implement SomeAbstraction
and call this dictionary via
responses.get(responseType).MethodOfYourAbstraction(SomeParams);
If you want to follow the principle of DI, you can inject this Dictionary in your client class.
My first cut would be to replace the if/else if structures with switch/case:
public Object processResponse(String responseType, Object response) {
switch(responseType) {
case CLIENT_REGISTERED: {
//code ...
}
case CLIENT_ABORTED: {
//code....
}
case DATA_SPLIT: {
//code...
}
From there I'd probably extract each block as a method, and from there apply the Strategy pattern. Stop at whatever point feels right.
The case you've describe seems to fit perfectly to the application of Strategy pattern. In particular, you've many variants of an algorithm, i.e. the code executed accordingly to the response of the remote server call.
Implementing the Stategy pattern means that you have to define a class hierachy, such the following:
public interface ResponseProcessor {
public void execute(Context ctx);
}
class ClientRegistered implements ResponseProcessor {
public void execute(Context ctx) {
// Actions corresponding to a client that is registered
// ...
}
}
class ClientAborted implements ResponseProcessor {
public void execute(Context ctx) {
// Actions corresponding to a client aborted
// ...
}
}
// and so on...
The Context type should contain all the information that are needed to execute each 'strategy'. Note that if different strategies share some algorithm pieces, you could also use Templeate Method pattern among them.
You need a factory to create a particular Strategy at runtime. The factory will build a strategy starting from the response received. A possibile implementation should be the one suggested by #Sattar Imamov. The factory will contain the if .. else code.
If strategy classes are not to heavy to build and they don't need any external information at build time, you can also map each strategy to an Enumeration's value.
public enum ResponseType {
CLIENT_REGISTERED(new ClientRegistered()),
CLIENT_ABORTED(new ClientAborted()),
DATA_SPLIT(new DataSplit());
// Processor associated to a response
private ResponseProcessor processor;
private ResponseType(ResponseProcessor processor) {
this.processor = processor;
}
public ResponseProcessor getProcessor() {
return this.processor;
}
}
My basic question: is there anything built that already does this automatically (doesn't have to be part of a popular library/package)? The main things I'm working with are Spring (MVC) and Jackson2.
I understand there are a few manual ways to do this:
Create a method in each class that serializes its specific properties into property=value& form (kind of stinks because it's a bunch of logic duplication, I feel).
Create a function that accepts an object, and uses reflection to dynamically read all the properties (I guess the getters), and build the string by getting each. I'm assuming this is how Jackson works for serialization/deserialization in general, but I really don't know.
Use some feature of Jackson to customly serialize the object. I've researched custom serializers, but it seems they are specific to a class (so I'd have to create one for each Class I'm trying to serialize), while I was hoping for a generic way. I'm just having trouble understanding how to apply one universally to objects. A few of the links:
http://techtraits.com/Programming/2011/11/20/using-custom-serializers-with-jackson/
http://wiki.fasterxml.com/JacksonHowToCustomSerializers
Use ObjectMapper.convertValue(object, HashMap.class);, iterate over the HashMap's key/value pairs, and build the string (which is what I'm using now, but I feel the conversions are excessive?).
I'm guessing there's others I'm not thinking of.
The main post I've looked into is Java: Getting the properties of a class to construct a string representation
My point is that I have several classes that I want to be able to serialize without having to specify something specific for each. That's why I'm thinking a function using reflection (#2 above) is the only way to handle this (if I have to do it manually).
If it helps, an example of what I mean is with, say, these two classes:
public class C1 {
private String C1prop1;
private String C1prop2;
private String C1prop3;
// Getters and setters for the 3 properties
}
public class C2 {
private String C2prop1;
private String C2prop2;
private String C2prop3;
// Getters and setters for the 3 properties
}
(no, the properties names and conventions are not what my actual app is using, it's just an example)
The results of serializing would be C1prop1=value&C1prop2=value&C1prop3=value and C2prop1=value&C2prop2=value&C2prop3=value, but there's only one place that defines how the serialization happens (already defined somewhere, or created manually by me).
So my idea is that I will have to end up using a form of the following (taken from the post I linked above):
public String toString() {
StringBuilder sb = new StringBuilder();
try {
Class c = Class.forName(this.getClass().getName());
Method m[] = c.getDeclaredMethods();
Object oo;
for (int i = 0; i < m.length; i++)
if (m[i].getName().startsWith("get")) {
oo = m[i].invoke(this, null);
sb.append(m[i].getName().substring(3) + ":"
+ String.valueOf(oo) + "\n");
}
} catch (Throwable e) {
System.err.println(e);
}
return sb.toString();
}
And modify it to accept an object, and change the format of the items appended to the StringBuilder. That works for me, I don't need help modifying this now.
So again, my main question is if there's something that already handles this (potentially simple) serialization instead of me having to (quickly) modify the function above, even if I have to specify how to deal with each property and value and how to combine each?
If it helps, the background of this is that I'm using a RestTemplate (Spring) to make a GET request to a different server, and I want to pass a specific object's properties/values in the URL. I understand I can use something like:
restTemplate.getForObject("URL?C1prop1={C1Prop1}&...", String.class, C1Object);
I believe the properties will be automatically mapped. But like I said, I don't want to have to make a different URL template and method for each object type. I'm hoping to have something like the following:
public String getRequest(String url, Object obj) {
String serializedUri = SERIALIZE_URI(obj);
String response = restTemplate.getForObject("URL?" + serializedUri, String.class);
return response;
}
where SERIALIZE_URI is where I'd handle it. And I could call it like getRequest("whatever", C1Object); and getRequest("whateverElse", C2Object);.
I think, solution number 4 is OK. It is simple to understand and clear.
I propose similar solution in which we can use #JsonAnySetter annotation. Please, see below example:
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
C1 c1 = new C1();
c1.setProp1("a");
c1.setProp3("c");
User user = new User();
user.setName("Tom");
user.setSurname("Irg");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.convertValue(c1, UriFormat.class));
System.out.println(mapper.convertValue(user, UriFormat.class));
}
}
class UriFormat {
private StringBuilder builder = new StringBuilder();
#JsonAnySetter
public void addToUri(String name, Object property) {
if (builder.length() > 0) {
builder.append("&");
}
builder.append(name).append("=").append(property);
}
#Override
public String toString() {
return builder.toString();
}
}
Above program prints:
prop1=a&prop2=null&prop3=c
name=Tom&surname=Irg
And your getRequest method could look like this:
public String getRequest(String url, Object obj) {
String serializedUri = mapper.convertValue(obj, UriFormat.class).toString();
String response = restTemplate.getForObject(url + "?" + serializedUri, String.class);
return response;
}
Lets we have c1.
c1.setC1prop1("C1prop1");
c1.setC1prop2("C1prop2");
c1.setC1prop3("C1prop3");
Converts c1 into URI
UriComponentsBuilder.fromHttpUrl("http://test.com")
.queryParams(new ObjectMapper().convertValue(c1, LinkedMultiValueMap.class))
.build()
.toUri());
After we will have
http://test.com?c1prop1=C1prop1&c1prop2=C1prop2&c1prop3=C1prop3