Spring, How to set error message from custom constraint validator at runtime - spring

I have this constraint for validating dhcp host addresses.
annotation class DHCPAddressConstraint(
val message: String = "Invalid dhcp address.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
val cidrField: String = "",
val addressRangeField: String = ""
)
class DHCPAddressValidator: ConstraintValidator<DHCPAd, Any> {
override fun isValid(obj: Any, context: ConstraintValidatorContext): Boolean {
val cidr = ReflectionUtils.get(obj, cidrField)
val addressRange = ReflectionUtils.get(obj, addressRangeField)
return isValidCIDR(cidr) && isValidAdressRange(cidr, addressRange)
}
}
So if something is invalid it would return just "Invalid dhcp address.". I want to set the error message to be more specific so why is it invalid. For example the dhcp address range may not be in the CIDR range or the user enters reserved IP address and so on. I expect to have error message like this "Invalid dhcp address due to ${reason}". how can I set the constraint error message at runtime?

you could take help of #ControllerAdvice & #ExceptionHandler
Please look at the example code below
#RestControllerAdvice
public class ApiExceptionController {
#ExceptionHandler(value = PageNotFoundApiException.class)
public ResponseEntity<Object> pageNotFoundApiException(PageNotFoundApiException exception){
return new ResponseEntity<>("Page Not Found 404", HttpStatus.NOT_FOUND);
}
}
You can also take a reference over this documentation
I hope, it helps!

Related

Convert data class to map to test http GET response body

I'm trying to test a GET to get all the StatusMapping objects created, however, I'm not sure what's the best approach to test this.
The response is returning a map whereas I was expecting a list of StatusMapping objects instead.
Should I convert the requests to a map?
Here's the Service code:
fun getAll(): ResponseEntity<List<StatusMapping>> {
return ResponseEntity<List<StatusMapping>>(statusMappingRepository.findAll(), HttpStatus.OK)
}
Here's the test
#Test
fun `Get all mappings created`() {
val requests = listOf(
StatusMapping("available", "available"),
StatusMapping("unavailable", "unavailable")
)
requests.forEach { statusMappingService.createMapping(it.toStatusMappingRequest()) }
val response = restTemplate.getForEntity(getRootUrl(), List::class.java)
assertEquals(response.body, requests)
}
Here's the error that I'm getting:
Expected :[{source=available, target=available}, {source=unavailable, target=unavailable}]
Actual :[StatusMapping(source=available, target=available), StatusMapping(source=unavailable, target=unavailable)]
Please start with replacing
val response = restTemplate.getForEntity(getRootUrl(), List::class.java)
with
val response = restTemplate.exchange(
getRootUrl(),
HttpMethod.GET,
null,
object : ParameterizedTypeReference<List<StatusMapping>>() {})
Assuming that restTemplate is instance of TestRestTemplate

consume/return a JSON response when executing flow using Spring boot API

I'm a beginner in corda and I'm trying to execute flows using Spring boot API. When I used:
#PostMapping(value = [ "create-iou" ], produces = [ TEXT_PLAIN_VALUE ] , headers = [ "Content-Type=application/x-www-form-urlencoded" ])
my flow is getting executed (by testing it using insomnia). But When I changed it to
#PostMapping(value = [ "create-iou" ], produces = [ APPLICATION_JSON_VALUE ], headers = [ "Content-Type=application/json" ])
It gives me a 406 not acceptable error: No body returned for response.
Here's the API I've created/copied:
#PostMapping(value = [ "create-iou" ], produces = [ TEXT_PLAIN_VALUE ] , headers = [ "Content-Type=application/x-www-form-urlencoded" ])
fun createIOU(request: HttpServletRequest): ResponseEntity<String> {
val iouValue = request.getParameter("iouValue").toInt()
val partyName = request.getParameter("partyName")
?: return ResponseEntity.badRequest().body("Query parameter 'partyName' must not be null.\n")
if (iouValue <= 0 ) {
return ResponseEntity.badRequest().body("Query parameter 'iouValue' must be non-negative.\n")
}
val partyX500Name = CordaX500Name.parse(partyName)
val otherParty = proxy.wellKnownPartyFromX500Name(partyX500Name) ?: return ResponseEntity.badRequest().body("Party named $partyName cannot be found.\n")
return try {
val signedTx = proxy.startTrackedFlow(::Initiator, iouValue, otherParty).returnValue.getOrThrow()
ResponseEntity.status(HttpStatus.CREATED).body("Transaction id ${signedTx.id} committed to ledger.\n")
} catch (ex: Throwable) {
logger.error(ex.message, ex)
ResponseEntity.badRequest().body(ex.message!!)
}
}
I would like to return something like this:
{
iouValue: 99,
lender: PartyA,
borrower: PartyB
}
When executing the flow using http endpoint.
You need to use the RPC connection libraries provided by Corda:
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCConnection
Take a look to this example to see how to use them.
You are not showing how your proxy is instantiate, but you need to instantiate a proxy to connect via RPC to the node, like so:
val rpcAddress = NetworkHostAndPort(host, rpcPort)
val rpcClient = CordaRPCClient(rpcAddress)
val rpcConnection = rpcClient.start(username, password)
proxy = rpcConnection.proxy
and once you have the proxy, you can create SpringBoot APIs to call that proxy that makes the RPC calls:
#RestController
#RequestMapping("/")
class StandardController(rpc: NodeRPCConnection) {
private val proxy = rpc.proxy
#GetMapping(value = ["/addresses"], produces = arrayOf("text/plain"))
private fun addresses() = proxy.nodeInfo().addresses.toString()
#GetMapping(value = ["/identities"], produces = arrayOf("text/plain"))
private fun identities() = proxy.nodeInfo().legalIdentities.toString()

Weird validation error handling in Micronaut

I have a controller action to serve my react front-end. It requires the validation messages in the special format:
#Transactional
#Post( uri = '{/id}', consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON )
HttpResponse save( #PathVariable #Nullable Long id, #Body Map body ){
def o = bindFromIdAndBody id, body
if( o.save( flush:true ) ){
log.info "version >> $o.version"
HttpResponse.ok o
}else{
log.info '-------------------------'
List errors = o.errors.fieldErrors.collect{ FieldError fe ->
fe.codes.findResult{ String c ->
messageSource.getMessage c, fe.arguments, null, Locale.default
} ?: fe.codes.last()
}
log.info "save failed for $o: $errors"
HttpResponse.badRequest( errors:errors )
}
}
When I call the action, I'm getting 400 Bad Request in my client, but instead of { errors:[ {..}, {..}, {..} ] style JSON, I see rather:
{
"message":"Validation Error(s) occurred during save() : Field error in object ... default message [Property [{0}] of class [{1}] cannot be blank]\r\n",
"path":"fullName",
"_links":{"self":{"href":"/person/42","templated":false}}
}
Also the else{} block is never reached, I don't get any further logs.
Any hints?
It appears, that in GORM configuration for Micronaut done via
compile 'io.micronaut.configuration:micronaut-hibernate-gorm'
the failOnError is set to true by default. That led to ValidationException being thrown on save() instead of populating o.errors.
To fix the issue I added the line
grails.gorm.failOnError: false
to my application.yml and now it's working like charm.

Retrieve #Authorization swagger codegen java

I work with swagger 2.0 to define a back end and trying to define security.
I end up with :
---
swagger: "2.0"
info:
version: 1.0.0
title: Foo test
schemes:
- https
paths:
/foo:
get:
security:
- Foo: []
responses:
200:
description: Ok
securityDefinitions:
Foo:
type: apiKey
name: X-BAR
in: header
Everything good till now, java codegen give me :
#ApiOperation(value = "", nickname = "fooGet", notes = "", authorizations = {
#Authorization(value = "Foo")
}, tags={ })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Ok") })
#RequestMapping(value = "/foo",
method = RequestMethod.GET)
default ResponseEntity<Void> fooGet() {
if(getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
} else {
log.warn("ObjectMapper or HttpServletRequest not configured in default FooApi interface so no example is generated");
}
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
I'm wondering, in the interface, how to retrieve "properly" the X-BAR header value.
I end up with :
#Autowired
private HttpServletRequest httpServletRequest;
httpServletRequest.getHeader("X-BAR")
which works , but is there a more proper way ?
Define a class "Foo" ? a doFilter ?
Thanks

Web service Rest using Angular2 and spring with Enum Types

I want to seed an object with format JSON that have an attribute with type enum
when I lanch my request I fet error 403
this is my service in front side
export enum DocumentComponentType {
DIV_12,
DIV_4_4_4,
DIV_4_8,
DIV_8_4,
DIV_6_6,
}
export interface DocumentComponent {
id: number;
type: DocumentComponentType;
// documentContents: DocumentContent[];
}
this.gridService.addDocumentComponent({id: 0, type: DocumentComponentType.DIV_8_4}, 6)
.subscribe(data => {
this.documentComponent = data;
},
error => alert('Erreur ' + error),
() => {
console.log("finished ");
}
);
and in server side
this is my class
public class DocumentComponent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
DocumentComponentType type;
#OneToMany(mappedBy = "documentComponent")
private List<DocumentContent> documentContents;
#ManyToOne
Document document;
DocumentComponent(){
}
}
and my enum
public enum DocumentComponentType {
DIV_12,
DIV_4_4_4,
DIV_4_8,
DIV_8_4,
DIV_6_6,
}
I get error 500 (Internal Server Error)
I get error 500 (Internal Server Error)
This means that there is an error on the server. The code you have posted is client side code.
Fix
Look at the server side logs (and or) attach a debugger to the server to see what is going on there.
More
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_Error The error is a generic error message which essentially means that something unexpected happened.

Resources