How to validate path parameter in microprofile - quarkus

Here key is pathParam. And even if I send the value of key greater than 9. It sends me valid response, instead of throwing validation error.
Curl request -
curl --location --request GET 'localhost:8080/v1/batch-tokens/11/action/count'
Code -
#Path("/v1/batch-tokens")
public class BatchTokenResource implements Serializable {
private static final Logger LOGGER = Logger.getLogger(BatchTokenResource.class.getName());
private static final String LOG_HEADER = "[" + BatchTokenResource.class.getSimpleName() + "]::";
#GET
#Path("/{key}/action/count")
public Response countTokenPerKey(
#PathParam("key") #Min(value = 0) #Max(value = 9)
#Pattern(regexp = "^\\d$") String key
) {
LOGGER.log(Level.INFO, () -> LOG_HEADER + "countTokenPerKey " +
"key=" + key
);
try {
Long tokenCount = 100L;
return Response.ok(new TokenModel(key, tokenCount)).build();
} catch (Exception ex) {
LOGGER.log(Level.WARNING, () -> LOG_HEADER + "countTokenPerKey failed." +
"key=" + key +
"exception=" + ex.getMessage()
);
throw ex;
}
}
}
I tried searching on quarkus.io/guide and internet, but only found docs to validate bean parameters.
Guide for validating bean parameters:
https://quarkus.io/guides/validation
https://microprofile.io/2019/07/11/validate-your-microservices-with-microprofile-and-bean-validation

Looks like the culprit is the type of the parameter:
String key
https://javadoc.io/doc/jakarta.validation/jakarta.validation-api/latest/jakarta/validation/constraints/Max.html
Supported types are:
BigDecimal
BigInteger
byte, short, int, long, and their respective wrappers
Note that double and float are not supported due to rounding errors (some providers might provide some approximative support).

Related

Azure Java SDK - set block blob to cool storage tier on upload

Is there a way to set the storage tier to “cool” at the blob level when uploading a block blob to Azure Storage using the Java SDK? The closest thing I can find is setStandardBlobTier() on BlobProperties, which is a protected method, so it can't be accessed.
The class CloudBlockBlob now has two uploadStandardBlobTier() methods which can be used to set the blob tier on a block blob on a standard storage account. e.g.
cloudBlockBlob.uploadStandardBlobTier(StandardBlobTier.COOL);
I searched the Azure Storage java SDK source code and setStandardBlobTier() method is protected method. I tried to create subclass of the BlobProperties Class and overwrite the setStandardBlobTier() method, but BlobProperties Class was decorated with the final keyword.
I also searched Azure Storage c# SDK, only get method was found.
It seems you cannot set blob tier via sdk , however you can set tier via rest api.
You could refer to the sample code as below:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
public class SetBlobTier {
private static final String account = "***";
private static final String key = "***";
public static void main(String args[]) throws Exception {
String urlString = "https://" + account + ".blob.core.windows.net/***/***?comp=tier";
HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
getFileRequest(connection, account, key);
// connection.connect();
connection.setDoInput(true);
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
out.flush();
out.close();
System.out.println("Response message : " + connection.getResponseMessage());
System.out.println("Response code : " + connection.getResponseCode());
BufferedReader br = null;
if (connection.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, String account, String key)
throws Exception {
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String stringToSign = "PUT\n" + "\n" // content encoding
+ "\n" // content language
+ "\n"// content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "\n"
+ "x-ms-date:" + date + "\n"
+ "x-ms-version:2015-02-21"+"\n" // headers
+ "/" + account + request.getURL().getPath(); // resources
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
request.setRequestMethod("PUT");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2015-02-21");
request.setRequestProperty("x-ms-access-tier", "Archive");
request.setRequestProperty("Authorization", auth);
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}
}
Hope it helps you.

BsonClassMapSerializer already registered for AbstractClassSerializer

I'm using the Mongo c# driver 2.0 and am running into BsonSerializer registration issues when registering AbstractClassSerializers for my Id value objects.
MongoDB.Bson.BsonSerializationException: There is already a serializer registered for type HistoricalEventId.
When I peek into the BsonSerializer I'm seeing that a BsonClassMapSerializer is already registered for my type.
I'm assuming that a BsonClassMapSerializer is being created for my entity types and it's also creating a BsonClassMapSerializer for the Id field as well. Has anyone run into this before? The Bson serializer code is shown below if that helps.
Sorry if the formatting is wrong, c# doesn't seem to be showing up well.
HistoricalEventIdBsonSerializer
public class HistoricalEventIdBsonSerializer : ToObjectIdBsonSerializer<HistoricalEventId>
{
public override HistoricalEventId CreateObjectFromObjectId(ObjectId serializedObj)
{
HistoricalEventId parsedObj;
HistoricalEventId.TryParse(serializedObj, out parsedObj);
return parsedObj;
}
}
ToObjectIdBsonSerializer
public abstract class ToObjectIdBsonSerializer<T> : AbstractClassSerializer<T> where T : class
{
private static readonly Type _convertibleType = typeof(IConvertible<ObjectId>);
public abstract T CreateObjectFromObjectId(ObjectId serializedObj);
public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonType = context.Reader.GetCurrentBsonType();
ObjectId value;
switch (bsonType)
{
case BsonType.Undefined:
value = ObjectId.Empty;
context.Reader.ReadUndefined();
break;
case BsonType.Null:
value = ObjectId.Empty;
context.Reader.ReadNull();
break;
case BsonType.ObjectId:
value = context.Reader.ReadObjectId();
break;
case BsonType.String:
value = new ObjectId(context.Reader.ReadString());
break;
default:
throw new NotSupportedException("Unable to create the type " +
args.NominalType.Name + " from the bson type " + bsonType + ".");
}
return this.CreateObjectFromObjectId(value);
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value)
{
if (value == null)
{
context.Writer.WriteObjectId(ObjectId.Empty);
}
else
{
if (!_convertibleType.IsAssignableFrom(args.NominalType))
{
throw new NotSupportedException("The type " + args.NominalType.Name +
" must implement the " + _convertibleType.Name + " interface.");
}
var typedObj = (IConvertible<ObjectId>)value;
context.Writer.WriteObjectId(typedObj.ToValueType());
}
}
}
IConvertible
public interface IConvertible<out T>
{
T ToValueType();
}
My assumption must have been correct because I just fixed this by doing the BsonSerializer registration before creating the MongoClient and getting the database. Hopefully this will help someone else.

spring security's searchForSingleEntryInternal method throws exception if record not found

I'm working on an application that uses Spring Security's searchForSingleEntryInternal method. Is there a way to do the same thing without throwing an exception if a record is not found? I want to be able to create a condition that handles missing records.
What I want to change
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
From this method
/**
* Internal method extracted to avoid code duplication in AD search.
*/
public static DirContextOperations searchForSingleEntryInternal(DirContext ctx, SearchControls searchControls,
String base, String filter, Object[] params) throws NamingException {
final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
final DistinguishedName searchBaseDn = new DistinguishedName(base);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry under DN '" + ctxBaseDn + "', base = '" + searchBaseDn + "', filter = '" + filter + "'");
}
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = resultsEnum.next();
// Work out the DN of the matched entry
DistinguishedName dn = new DistinguishedName(new CompositeName(searchResult.getName()));
if (base.length() > 0) {
dn.prepend(searchBaseDn);
}
if (logger.isDebugEnabled()) {
logger.debug("Found DN: " + dn);
}
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
}
} catch (PartialResultException e) {
LdapUtils.closeEnumeration(resultsEnum);
logger.info("Ignoring PartialResultException");
}
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, results.size());
}
return results.iterator().next();
}
}
I'm somewhat new to spring and maybe I'm missing something obvious. Any advice would be much appreciated
easy fix, just had to copy over the searchForSingleEntryInternal method from Spring Security and place it in my own project. From there I was able to tweak the exception handling so the application didn't come to a grinding halt if a record wasn't found.

Gson : parsing json string to java arraylist like modeling

I tried to parse a Json response I guet from my limesurvey server to Java, however I don't see what type of Class I should create it.
Here is the json string that I want to parse into a java object :
{"id":1,"result":{"gid":"1","type":"L","help":"Veuillez entrer votre niveau d'\u00e9tudes \u00e0 l'INPT.","language":"fr","sid":"796246","question_order":"3","question":"<p>\r\n\tvotre niveau d'\u00e9tudes \u00e0 l'INPT :<\/p>\r\n","answeroptions":{"A1":{"answer":"INE1","assessment_value":"0","scale_id":"0"},"A2":{"answer":"INE2","assessment_value":"1","scale_id":"0"},"A3":{"answer":"INE3","assessment_value":"1","scale_id":"0"}}},"error":null}
In order to parse it I created the following classes :
public class Answer
{
String answer;
int assessment_value;
int scale_id;
#Override
public String toString() {
return "answer : "+answer + " - assessment_value : " + assessment_value + " - scale_id :" + scale_id;
}
}
public class answerOptions
{
String a;
Answer t;
}
public class QuestionProperties
{
int gid;
String type;
String help;
String language;
int sid;
int question_order;
String question;
ArrayList<answerOptions> answeroptions;
#Override
public String toString() {
return "gid : "+gid + " - type : " + type + " - help :" + help + " - language :" + language + " - sid :" + sid + " - question_order :" + question_order + " - question :" + question;
}
}
public class getQuestionProperties
{
int id;
QuestionProperties result;
String error;
#Override
public String toString() {
return "id : "+id + " - result : " + result + " - error :" + error;
}
}
The problem I have is that I declared "answeroptions" as an array while it is not, however I can't know for sure the number of options in there, I tried a class that works like a pair of a sort but it's not working ?? any ideas on how to model this problem without loosing genrality since I want a method to automatically parse this whatever the number of options !!
You are almost doing well. Just change it to Map<String,Answer> instead of ArrayList<answerOptions> as per the JSON string. Here "A1", "A2" and "A3" are keys of the Map.
sample:
class QuestionProperties {
...
Map<String,Answer> answeroptions;
}
In JSON String anything enclosing inside
{...} is converted to Map or custom POJO class Object
[...] is converted to ArrayList
Learn more... about JSON and follow this post
Note: Follow Java Naming convention for class name. Encapsulate all variables by making private and use proper getter/setter methods.

Using JavaMail reading from gmail issue

I am having problems reading mails from gmail (pop3) using javamail. I have a code that woks perfectly if the mail was sent from ubuntu's Thnderbird. How ever if the mail was originally sent from mac it fails.
This is the code I ham using:
private static final String UNKNOWN_BRAND_PATH = "UNKNOWN";
public static final String FOLDER_NAME = "INBOX";
private static Logger LOG = org.slf4j.LoggerFactory.getLogger(LzMailRecieverService.class);
#Value("${lz.mail.address}")
private String lzMailUserName;
#Value("${lz.mail.password}")
private String lzMailPassword;
#Value("${lz.mail.tmp.folder}")
private String lzMailTmpFolder;
public Store connect() throws Exception {
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties pop3Props = new Properties();
pop3Props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
pop3Props.setProperty("mail.pop3.socketFactory.fallback", "false");
pop3Props.setProperty("mail.pop3.port", "995");
pop3Props.setProperty("mail.pop3.socketFactory.port", "995");
URLName url = new URLName("pop3", "pop.gmail.com", 995, "", lzMailUserName, lzMailPassword);
Session session = Session.getInstance(pop3Props, null);
Store store = new POP3SSLStore(session, url);
store.connect();
return store;
}
public Folder openFolder(Store store) throws MessagingException {
Folder folder = store.getDefaultFolder();
folder = folder.getFolder(FOLDER_NAME);
folder.open(Folder.READ_ONLY);
return folder;
}
public List<MailDetails> readAttachement(Folder folder) throws IOException, MessagingException {
Message[] messages = folder.getMessages();
List<MailDetails> mailDetails = new ArrayList<MailDetails>();
for (Message message : messages) {
logMailDetails(message);
if (message.getContent() instanceof Multipart) {
Multipart multipart = (Multipart) message.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
continue; // dealing with attachments only
}
InputStream is = bodyPart.getInputStream();
String uid = getUid(message);
String to = getTo(message);
String from = getFrom(message);
File d = new File(lzMailTmpFolder + File.separator + uid);
if (d.exists() == false) {
d.mkdir();
}
File f = new File(d, new DateTime().getMillis() + "-" + bodyPart.getFileName());
FileOutputStream fos = new FileOutputStream(f);
IOUtils.copy(is, fos);
MailDetails md = new MailDetails(to, from, f, uid);
mailDetails.add(md);
}
}
else {
LOG.warn("Message conteant is not Multipart " + message.getContentType() + " skipping ...");
}
}
return mailDetails;
}
private String getFrom(Message message) throws MessagingException {
Address[] froms = message.getFrom();
return froms[0].toString();
}
private String getTo(Message message) throws MessagingException {
Address[] tos = message.getAllRecipients();
return tos[0].toString();
}
public void logMailDetails(Message m) throws MessagingException {
Address[] f = m.getFrom();
if (f != null) {
for (int j = 0; j < f.length; j++)
LOG.debug("FROM: " + f[j].toString());
}
Address[] r = m.getRecipients(Message.RecipientType.TO);
if (r != null) {
for (int j = 0; j < r.length; j++) {
LOG.debug("TO: " + r[j].toString());
}
}
LOG.debug("SUBJECT: " + m.getSubject());
Date d = m.getSentDate();
LOG.debug("SendDate: " + d);
}
private String getUid(Message m) throws MessagingException {
try {
Address[] tos = m.getAllRecipients();
String to = tos[0].toString();
to = to.split("#")[0];
String[] parts = to.split("\\+");
return parts[parts.length - 1];
}
catch (Exception e) {
LOG.error("Failes to extract brand hash from email address " + Lists.newArrayList(m.getFrom()));
return UNKNOWN_BRAND_PATH;
}
}
The problem is that for the mails originally created in mac bodyPart.getDisposition() always returns null. No matter what I have tried I could not understand which part is the attachment part (this is what I really need: extracting the attachment from the mail).
I have looked all over the web to find ewhat is the reason for that and I failed to find an answer. How ever I found the below note written by Juergen Hoeller that indicates that there might be an issue here (more details here: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/mail/javamail/MimeMessageHelper.html)
Warning regarding multipart mails: Simple MIME messages that just contain HTML text but no inline elements or attachments will work on more or less any email client that is capable of HTML rendering. However, inline elements and attachments are still a major compatibility issue between email clients: It's virtually impossible to get inline elements and attachments working across Microsoft Outlook, Lotus Notes and Mac Mail. Consider choosing a specific multipart mode for your needs: The javadoc on the
MULTIPART_MODE constants contains more detailed information.
Is there any example or explnation regarding using JavaMail if the mails are sent from Mac??
Yosi
The "disposition" is at best a hint; it's not required to be included.
These JavaMail FAQ entries might help:
How do I tell if a message has attachments?
How do I find the main message body in a message that has attachments?
What are some of the most common mistakes people make when using JavaMail?

Resources