PdfReader constructor on Inputstream or Byte[] with interface ExternalDecryptionProcess - itext

I need to call the constructor of PdfReader with the interface ExternalDecryptionProcess from an inputStream or byte array.
Is it possible to add a new constructor to the PdfReader class like the following:
PdfReader(final InputStream is, Certificate certificate, final ExternalDecryptionProcess externalDecryptionProcess)
OR
PdfReader(final byte pdfIn[], Certificate certificate, final ExternalDecryptionProcess externalDecryptionProcess)
The master constructor is private so I couldn't directly call it
Thanks
Jamil

Related

Public key encoding changes

I've generated a public key using elliptic curves, but whenever I get the encoding of the key, it changes. I would like to use the encoding for a public address of a blockchain I am implementing. See below
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.ECGenParameterSpec;
class Scratch {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
keyGen.initialize(ecSpec);
KeyPair kp = keyGen.generateKeyPair();
PublicKey k = kp.getPublic();
byte[] one = k.getEncoded();
byte[] two = k.getEncoded();
System.out.println(one);
System.out.println(two);
}
}
With output
[B#4eec7777
[B#3b07d329
Does anyone know why this is happening? My guess is that it is the expected behavior and I am just misunderstanding something fundamental here.
You are printing the memory address of the byte[], not the key itself. You can't "print" a byte array because it is binary data, you need to encode it somehow first. Hex and base64 are both good encodings for displaying binary data. For memory, other blockchain implementations like to use base58.
Here is an example using base64:
String b64Str = Base64.getEncoder().encodeToString(one);
System.out.println(b64Str);

Is using default method in an interface a good pattern to avoid code duplications?

We have a lot of code duplication in data holder classes that can be serialized to a XML string:
public String toXml() throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(this.getClass());
final Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
final StringWriter stringWriter = new StringWriter();
marshaller.marshal(this, stringWriter);
return stringWriter.toString();
}
Why not move this code to a single interface with default implementation? So a simple implements ToXmlUtf8 would be enough to share the default implementation and avoid code duplicates:
public interface ToXml {
default String toXml() throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(this.getClass());
final Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
final StringWriter stringWriter = new StringWriter();
marshaller.marshal(this, stringWriter);
return stringWriter.toString();
}
}
Has anybody done this before successfully?
Other solutions?
I could also imagine using an annotation to generate this code.
Are there any ready to use solutions available?
Yes, default methods can be used in that way.
Although the intended use case of default methods is adding new functionality to existing interfaces without breaking old code, default methods have other uses as well. Default methods are also used in interfaces which were added in Java 8, such as in java.util.Predicate, so even the Java designers recognized that adding new functionality to existing interfaces is not the only valid use of default methods.
A disadvantage could be that the implemented interfaces are part of a class's public contract, but in your case this does not seem to be a problem.
If you're using the exact same method then an interface won't help, what you want to do is make a static method and put that in a util class

Array Multipart[] file upload using Feign client

I am trying to upload Array of Multipart file object using feign client.
This is the service am trying to call using Feign client.
public ResponseEntity<Object> manageFileUpload(#RequestParam("files") MultipartFile[] files)
I tried using,Feign client Annotation,
#FeignClient(value = "UPLOADUTILITIES", configuration = Upload.MultipartSupportConfig.class, fallback = UploadFallback.class)
My Method,
#RequestMapping(name = "upload", value = "/object", method = RequestMethod.POST)
#Headers("Content-Type: multipart/form-data")
ResponseEntity<Object> manageFileUpload(#Param("files") MultipartFile[] files);
I was rewarded by the error,
"message": "Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[0]->org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[\"inputStream\"]->java.io.FileInputStream[\"fd\"])",
Then by referring this link.I tried in my client side, the blow code.
public class MultipartSupportConfig {
#Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
#Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
Then by the code example, i changed my MultiPart File object into File Object.Now my request got fired, but i got Not a multipart request.
I tried this https://github.com/pcan/feign-client-test#feign-client-test,
I created a class and used the encoder class, and changed my encoder as FeignSpringFormEncoder,
Still I am getting No serializer found error.
Could anyone share a simple client, server example with Array of Multipart file request, using feign cleint. Thanks!

Reading from streams instead of files in spring batch itemReader

I am getting a csv file as a webservice call which needs to be laoded. Right now I am saving it in temp directory to provide it as setResource to Reader.
Is there a way to provide stream(byte[]) as is instead of saving the file first?
The method setResource of the ItemReader takes a org.springframework.core.io.Resource as a parameter. This class has a few out-of-the-box implementations, among which you can find org.springframework.core.io.InputStreamResource. This class' constructor takes a java.io.InputStream which can be implemented by java.io.ByteArrayInputStream.
So technically, yes you can consume a byte[] parameter in an ItemReader.
Now, for how to actually do that, here are a few ideas :
1) Create your own FlatFileItemReader (since CSV is a flat file) and make it implement StepExecutionListener
public class CustomFlatFileItemReader<T> extends FlatFileItemReader<T> implements StepExecutionListener {
}
2) Override the beforeStep method, do your webservice call within and save the result in a variable
private byte[] stream;
#Override
public void beforeStep(StepExecution stepExecution) {
// your webservice logic
stream = yourWebservice.results();
}
3) Override the setResource method to pass this stream as the actual resource.
#Override
public void setResource(Resource resource) {
// Convert byte array to input stream
InputStream is = new ByteArrayInputStream(stream);
// Create springbatch input stream resource
InputStreamResource res = new InputStreamResource(is);
// Set resource
super.setResource(res);
}
Also, if you don't want to call your webservice within the ItemReader, you can simply store the byte array in the JobExecutionContext and get it in the beforeStep method with stepExecution.getJobExecution().getExecutionContext().get("key");
I am doing right now with FlaFileItemReader, reading a file from Google Storage. No needed to extends:
#Bean
#StepScope
public FlatFileItemReader<MyDTO> itemReader(#Value("#{jobParameters['filename']}") String filename) {
InputStream stream = googleStorageService.getInputStream(GoogleStorage.UPLOADS, filename);
return new FlatFileItemReaderBuilder<MyDTO>()
.name("myItemReader")
.resource(new InputStreamResource(stream)) //InputStream here
.delimited()
.names(FIELDS)
.lineMapper(lineMapper()) // Here is mapped like a normal File
.fieldSetMapper(new BeanWrapperFieldSetMapper<MyDTO>() {{
setTargetType(MyDTO.class);
}})
.build();
}

BouncyCastle AlgorithmIdentifier

How can i create a new instance of org.bouncycastle.asn1.x509.AlgorithmIdentifier of RSA OAEP? in order to be able to use it here:
JceKeyTransRecipientInfoGenerator(java.security.cert.X509Certificate recipientCert, org.bouncycastle.asn1.x509.AlgorithmIdentifier algorithmIdentifier)
with current BouncyCastleVersions you can use a constant from org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP);
It is as simple as creating object from string representation of RSA with OAEP oid
AlgorithmIdentifier id = AlgorithmIdentifier.getInstance("1.2.840.113549.1.1.7");
in recent versions of BouncyCastle >1.50 this API has been removed and getInstance takes only ASN1Sequence and AlgorithmIdentifier. So there is no option, but to use constructor:
AlgorithmIdentifier id = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP);