When I use spring-mvc, I always use spring formatter to format a string to Java Bean. So, I implement org.springframework.format.Formatter interface.
Despite I implement two methods(print(),parse()), the print method has never been used. Because I just use parse()method format a String to Java Bean and never format Java Bean to String.
So, my question is, what situation does the print() will be called? Or when I need format a Java Bean to String.
Formatters can be used for parsing and printing Dates, Timestamps, and general numeric data.
This means, as you already pointed out, that we can customize the way parsing is handled for a specific type by overriding the parse() method.
It also means that we can provide custom print behaviour by overriding the print() method.
So, what's print's use case?
Let's put an example.
Suppose you have a serial number type composed of 4 segments —e.g., 1111-2222-3333-4444.
public class SerialNumber {
private int segment1;
private int segment2;
private int segment3;
private int segment4;
//Some getters and setters;
}
Now, we'll implement a Formatter class that can parse an input like the one shown above. For brevity's sake I'll avoid try-catch blocks and validation logic:
public class SerialNumberFormatter implements Formatter {
public SerialNumber parse(String input, Locale locale) {
//Some code here to validate input
//Split the input into segments
String[] result = speech.split("-");
return new SerialNumber(Integer.parseInt(result[0],
Integer.parseInt(result[1],
Integer.parseInt(result[2],
Integer.parseInt(result[3])
}
}
So, this way we managed to parse the Serial Number. But we already knew this. Now, let's suppose we'd like to show a SerialNumber stored in our DB to the end-user in the following format "SN: 1111-2222-3333-4444". We need to print the object somehow. That logic can be implemented inside the print() method.
Completing our Formatter class:
public class SerialNumberFormatter implements Formatter {
public SerialNumber parse(String input, Locale locale) {
//Some code here to validate input
//Split the input into segments
String[] result = speech.split("-");
return new SerialNumber(Integer.parseInt(result[0],
Integer.parseInt(result[1],
Integer.parseInt(result[2],
Integer.parseInt(result[3])
}
public String print(SerialNumber sn, Locale locale) {
//Some code here to validate the sn
return String.format("SN: %d-%d-&d-%d", sn.getSegment1,
sn.getSegment2,
sn.getSegment3,
sn.getSegment4)
}
}
To sum up, Formatter allows us to encapsulate logic related to parsing and printing, that otherwise would need to be coded into a business or service layer.
Remember that a Formatter can also be composed of Parser and Printer classes. So, a print() method may contain printing logic much more complicated than just building a String. It could encapsulate logic to format a POJO and write it to a file. It could also return a JSON or an XML as output.
Take it mainly as an abstraction that lets us decouple formatting logic from the rest of our code.
Formatter interface is also a core piece of the Spring Framework. You can implement custom Formatters and then register them into the framework for different tasks. You can take a look at this Baeldung's article: https://www.baeldung.com/thymeleaf-in-spring-mvc
In Section 8, you'll appreciatte how a Formatter is implement and then registered to Spring MVC to convert and show data in the front-end.
Related
I do have some entity class (code without annotations for simplified example)
class User {
public String id;
public String name;
}
Now I want to output this via an API, but I want to structure my response in a special format, like
{
"data": {
"id": 1,
"name": "mars3142"
}, // user object or another entity or list...
"meta": ...,
"error": ...
}
The meta and/or error data should only be visible in special situations (like RuntimeExceptions). Where is the best place to transform my entity results into the normalized response? Do I need to write a filter for that? Does anybody has a sample code for that?
I would suggest to implement something this:
public abstract class BaseResponse {
// Meta data
// Consider defining fields here needed for happy-path and error-responses
// Contains common tracking fields, e.g. correlationId, requestId
}
public class ErrorResponse extends BaseResponse {
// Error Fields
}
public class Response extends ErrorResponse {
// Entity-object in your case
}
I guess you can build your response like setting response from DAO to above suggested structure in controller layer. For error-responses (in case of RuntimeExceptions), they're standardly build and returned in #ControllerAdvice or other.
Some patterns of exception handling are explained in Error Handling for REST with Spring | Baeldung.
Regarding your 2 questions:
Design: The proper place for this response-mapping depends on the scope (all responses or just some) and existing components in your application's response layer.
Patterns and Web-Framework concepts: I would not use the response-filters or -interceptors of your web-framework. Those should be used for cross-cutting concerns, or for chained processes (e.g. security, authorization, enrichment, sanitation).
Instead I would use the web-frameworks concepts and components that are responsible for response-representations, like ResponseEntity (HTTP-response representation, ControllerAdvice (error-handling), HttpMessageConverter.
There are 3 ways you could "wrap" your objects into uniform JSON-response models:
Annotate class with the custom #JsonRootName as data and in special cases add meta and/or error attributes (through e.g. embedding into a wrapper or using a mixin)
A JSON custom serializer that could extend from BeanSerializer which wraps this and any class uniformly in your given outer structure
Modify Spring's MappingJackson2HttpMessageConverter to wrap any returned response object into the predefined JSON-structure
You could iterate from the simplest (1.) to the most complex (3.). Some iteration code (like 2.) can be reused in the next (3.).
1. Use a Wrapper Class
The first is rather a simple start where you can implement the "normalization" within controller-methods. You could for example put the object (serialized as data) into the "empty" meta-structure (wrapper-class) with an empty JsonNode, and meta or error properties.
2. Define a Custom Serializer
The second is pretty flexible and can be tested well in isolation (not even depending on Spring). It would allow to implement the complete object-wrapping in one place.
3. Customize Spring's HTTP Message Converter
The third is similar to the second but requires some knowledge about Spring's message-converters and allows you to transform each response-object to a specific JSON-response using Jackson's ObjectMapper.
Sample code can be found online, e.g. at Baeldung's Jackson or Spring tutorials, Springframework Guru articles.
I used the solution from https://stackoverflow.com/a/72355056/708157 and transformed it a little bit.
Now my classes are that way
public class BaseResponse<T> {
boolean success;
T data;
Error error;
}
public class Error {
...
}
And every api response is now ResponseEntity<BaseResponse<XYZ>>. This way, I can setup my default structure and my classes are lose coupled, because I can use every class for T within my BaseResponse.
I am new to Springboot reactive
I was asked to call the following endpoint and return todays weather data only:
https://api.weather.gov/gridpoints/MLB/33,70/forecast
I believe I need to use something like this...
WebClient.create().get()
.uri("https://api.weather.gov/gridpoints/MLB/33,70/forecast")
.retrieve()
.bodyToMono(WeatherClass.class)
.block();
Do I need to map out an entire java object to match the JSON at the endpoint? is there an easy way to perhaps just grab the a certain piece of the JSON?
How would I handle something like the #context annotation in the JSON.
The WebClient in spring boot automatically uses Jackson's ObjectMapper to unmarshall json to a java object when the content type of the response is application/json. So there is no need to pull in any additional libraries or have to write any specific unmarshalling code, unless you want to use an alternate json-to-java library.
When using Jackson, you don't need to map every field in the json to your java object. You can annotate your java class with #JsonIgnoreProperties to inform jackson to ignore any properties that may appear in the json but do not have a matching field in your java object.
An example WeatherClass in which you want only the #context and forecastGenerator unmarshalled would look something like this
#JsonIgnoreProperties
public class WeatherClass {
private final List<Object> context;
private final WeatherProperties weatherProperties;
public WeatherClass(#JsonProperty("#context") List<Object> context,
#JsonProperty("properties") WeatherProperties weatherProperties) {
this.context = context;
this.weatherProperties = weatherProperties;
}
private class WeatherProperties {
private final String forecastGenerator;
private WeatherProperties(#JsonProperty("forecastGenerator") String forecastGenerator) {
this.forecastGenerator = forecastGenerator;
}
}
}
Note
#context seems to be an array that can contain multiple types (both objects and strings in your example). I've used Object to work around this but obviously isn't the most graceful solution but should be adequate to demonstrate how Jackson works
Alternatively, you can unmarshall the response to a JsonNode, which you can then use to traverse the structure of the json without converting it to a java object. For example
String forecastGenerator = WebClient.create().get()
.uri("https://api.weather.gov/gridpoints/MLB/33,70/forecast")
.retrieve()
.bodyToMono(JsonNode.class)
.block().get("properties").get("forecastGenerator").toString()
There are many other annotations provided by Jackson that can used to define how the unmarshaller functions. Too many to cover here. See Jackson Deserialisation Annotations
I am writing a Springboot REST endpoint and want to consume XML or JSON requests for a simple service. In either case I want Spring to construct an #RequestBody pojo WITHOUT annotating any of the POJO. Is this OK? Safe? Performant?
I was reading this which told me about configuration by exception. To me this means if I structure my request to contain the exact name and case as the POJO member variables I want to populate the #RequestBody will be able to create my class SomeRequest.
If this is my REST endpoint:
#RequestMapping(value = GET_FOR_SOMETHING, method = RequestMethod.POST,
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},,
produces = {MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody
StatusResponse<Boolean> getMpdForReqest(#RequestBody SomeRequest request)
And this is my POJO:
public class SomeRequest {
String one;
String two;
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
public String getTwo() {
return two;
}
public void setTwo(String two) {
this.two = two;
}
}
My JSON request:
{
"one": "str",
"two": "str"
}
My XML request:
<SomeRequest>
<one>str</one>
<two>str</two>
</SomeRequest>
My question is: why should I not do this or is it perfectly fine?
Thank you all.
TLDR; It is perfectly fine.
Is this OK? Safe? Performant?
Yes, it is as performant as it's annotated cousin, if you take program efficiency into account.
If you take the Programmer efficiency into account, it is much more efficient as the developer doesn't have to deal with a bunch of annotations.
Speaking of Programmer efficiency, I would encourage you to use project Lombok instead of crapping your POJO with bunch of getter and setter methods, that's what cool kids do now a days.
Catch
This will work fine as long as your json fields are one word and small case.
When you have multi-word field name, Java standard is the camelCase and usually JSON standard is the snake_case. In this case, you can either have a Class level Annotation (one per class, so not much ugly). Or, since you are using spring boot, you can use an application wide property (spring.jackson.property-naming-strategy = SNAKE_CASE ).
If you have weird json field names with spaces in between, you might need to use #JsonProperty annotation. Remember, this is a perfectly valid json
{
"just a name with a space" : "123"
}
POJO as RequestBody works perfectly fine. Just note that Spring however will return 400 - Bad Request for every request that can not be mapped to the #RequestBody annoted object.
I have a gradle multiproject with 2 subprojects trying to emulate an hexagonal architecture :
rest-adapter
application layer
I don't want the application services to expose the domain models and do'nt want to force a specific representation as output. So I would like something like application services consume 2 args (a command and something) and return a T. The client configures the service.
The rest adapter doesn't ave access to the domain model, so I can't return the domain models and let the adapter creates its representation.
What about the something. I tried :
have a signature <T> List<T> myUseCase(Command c, Function<MyDomainModel, T> fn). The application layer is the owner of transformations functions (because the signature uses MyDomainModel) and exposes a dictionnary of function. So the rest controller references one of the Fn. It works. And I'm searching of a better way. More elegant way if it exists.
have a signature <T> List<T> myUseCase(Command c, FnEnum fn) For each enum I have associated a Function. With this, I found the signature more elegant : the consumer provides which transformation it wants from an enum. But doesn't work cause the generic method doesn't compile. The cannot be resolved. Currently, I didn't find a way.
something with java 8 consumer or supplier or something else but I failed to wrap my head around.
I'm feeling there's a more elegant solution for this kind of problem : a service which accepts a function that transforms and build an output that the client provides.
I think that what you need to implement is the so called "Data Transformer" pattern.
Imagine that you have a use case that returns a certain domain object (for example "User"), but you shouldn't expose domain to clients. And you want every client to choose the format of the returned data.
So you define a data transformer interface for the domain object:
public interface UserDataTransformer {
public void write ( User user );
public String read();
}
For every output format your clients need you define a class implementing the interface. For example if you want to represent the User in XML format:
public class UserXMLDataTransformer implements UserDataTransformer {
private String xmlUser;
#Override
public void write(User user) {
this.xmlUser = xmlEncode ( user );
}
private String xmlEncode(User user) {
String xml = << transform user to xml format >>;
return xml;
}
#Override
public String read() {
return this.xmlUser;
}
}
Then you make your application service depends on the data trasnsformer interface, you inject it in the constructor:
public class UserApplicationService {
private UserDataTransformer userDataTransformer;
public UserApplicationService ( UserDataTransformer userDataTransformer ) {
this.userDataTransformer = userDataTransformer;
}
public void myUseCase ( Command c ) {
User user = << call the business logic of the domain and construct the user object you wanna return >> ;
this.userDataTransformer.write(user);
}
}
And finally, the client could look something like this:
public class XMLClient {
public static void main ( String[] args ) {
UserDataTransformer userDataTransformer = new UserXMLDataTransformer();
UserApplicationService userService = new UserApplicationService(userDataTransformer);
Command c = << data input needed by the use case >>;
userService.myUseCase(c);
String xmlUser = userDataTransformer.read();
System.out.println(xmlUser);
}
}
I've consider that the output is a String, but you could use generics maybe to return any type you want.
I haven't mentioned it, but this approach injecting the transformer into the application service follows the "port and adapters" pattern. The transformer interface would be the port, and every class implementing it would be an adapter for the desired format.
Also, this was just an example. You can use a dependency injection framework like Spring in order to create the component instances and wire them all. And also you should use the composition root pattern to do it.
Hope this example helped.
I'm feeling there's a more elegant solution for this kind of problem : a service which accepts a function that transforms and build an output that the client provides.
You are sending data across the boundary between the application and the REST layer (and presumably between the application and the REST consumer); it may be useful to think about messaging patterns.
For example, the application can define a service provider interface that defines a contract/protocol for accepting data from the application.
interface ResponseBuilder {...}
void myUseCase(Command c, ResponseBuilder builder)
The REST adapter provides an implementation of the ResponseBuilder that can take the inputs and generate some useful data structure from them.
The response builder semantics (the names of the functions in the interface) might be drawn from the domain model, but the arguments will normally be either primitives or other message types.
CQS would imply that a query should return a value; so in that case you might prefer something like
interface ResponseBuilder<T> {
...
T build();
}
<T> T myUseCase(Command c, ResponseBuilder<T> builder)
If you look carefully, you'll see that there's no magic here; we've simply switched from having a direct coupling between the application and the adapter to having an indirect coupling with the contract.
EDIT
My first solution is using a Function<MyDomainModel, T> which is a bit different from your ResponseBuilder ; but in the same vein.
It's almost dual to it. You'd probably be a little bit better off with a less restrictive signature on myUseCase
<T>
List<T> myUseCase(Command c, Function<? super MyDomainModel, T> fn)
The dependency structure is essentially the same -- the only real difference is what the REST adapter is coupled to. If you think the domain model is stable, and the output representations are going to change a lot, then the function approach gives you the stable API.
I suspect that you will find, however, that the output representations stabilize long before the domain model does, in which case the ResponseBuilder approach will be the more stable choice.
Using Grails 1.2.2, I'm working on binding a structured property (CC expiration Date) to a java.util.Date but only for specific Domain and Commands objects.
I've found the StructuredPropertyEditor interface, but the only way that I've found to register it is to use the PropertyEditorRegistrar and register the editor for the java.util.Date class (much like this example)
I don't want all of my dates to use my custom StructuredPropertyEditor. How do I apply the StructuredPropertyEditor selectively to specific targets like certain Command & Domain Classes?
can't you specify the custom type (cc expiration date model) for the registration?. It worked for me for money representation
public class CCExpirationPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(CCExpirationClass.class, new CCExpirationEditor());
}
}
With Grails most of the Data Binding is by type and convention, whereas in raw Spring you might manually construct this stuff.
After researching this a while, the closest that I could get in Grails was to register a custom editor for with a specific propertyName / Class type. I wasn't able to make it specific to a specific command object or domain.
class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
propertyEditorRegistry.registerCustomEditor(Date.class, "cardExpirationDate", new PaymentCardExpirationDateStructuredPropertyEditor(new SimpleDateFormat("MM/yy"), true))
}
}