Jekyll2024-11-18T22:33:39+00:00https://jsedano.dev/feed.xmljsedano.devthis is my personal dev blog. hope you find something of interest here. I post about software development.juan sedanoSimple web QR maker with zxing and Thymeleaf2024-06-17T06:00:00+00:002024-06-17T06:00:00+00:00https://jsedano.dev/java/thymeleaf/qr/2024/06/17/simple-qrEncode text into QR Code with zxing and display it using thymeleaf. Live demo here.

You can find the complete code for this here.

This is the method to encode a String into an image, and then encode the image into a base 64 String that represents the png, based around the code in this tutorial.

QRCreator.java

  private String unsafeCreateQRImage(String qrCodeText, int size)
      throws WriterException, IOException {
    // Create the ByteMatrix for the QR-Code that encodes the given String
    Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<>();
    hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
    BitMatrix byteMatrix =
        qrCodeWriter.encode(qrCodeText, BarcodeFormat.QR_CODE, size, size, hintMap);
    // Make the BufferedImage that are to hold the QRCode
    int matrixWidth = byteMatrix.getWidth();
    BufferedImage image = new BufferedImage(matrixWidth, matrixWidth, BufferedImage.TYPE_INT_RGB);
    image.createGraphics();

    Graphics2D graphics = (Graphics2D) image.getGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, matrixWidth, matrixWidth);
    // Paint and save the image using the ByteMatrix
    graphics.setColor(Color.BLACK);

    for (int i = 0; i < matrixWidth; i++) {
      for (int j = 0; j < matrixWidth; j++) {
        if (byteMatrix.get(i, j)) {
          graphics.fillRect(i, j, 1, 1);
        }
      }
    }
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ImageIO.write(image, "png", bos);
    byte[] imageBytes = bos.toByteArray();

    Base64.Encoder encoder = Base64.getEncoder();
    return encoder.encodeToString(imageBytes);
  }

Use this on the controller for the thymeleaf templates.

SimpleQRController.java

  @RequestMapping("/")
  public String newRandomSelect(Model model) {
    model.addAttribute("textAndQRImage", new TextAndQRImage());
    return "inputQR";
  }

  @RequestMapping("/show")
  public String showQR(Model model, TextAndQRImage textAndQRImage, HttpSession session) {
    if (Objects.isNull(textAndQRImage.getText()) || textAndQRImage.getText().isEmpty()) {
      return "redirect:/simpleqr/";
    }
    String qrImage = qrCreator.createQRImage(textAndQRImage.getText(), 800);
    if (Objects.isNull(qrImage) || qrImage.isEmpty()) {
      return "redirect:/simpleqr/";
    }
    textAndQRImage.setText(textAndQRImage.getText());
    textAndQRImage.setBase64Image(qrCreator.createQRImage(textAndQRImage.getText(), 800));

    model.addAttribute("textAndQRImage", textAndQRImage);
    return "showQR";
  }

Part of inputQR.html that asks for the text that will be encoded into a QR code.

    <form action="/simpleqr/show" th:object="${textAndQRImage}" method="POST">

        <input type="text" placeholder="input text here" th:field="*{text}">

        <button type="submit">Generate QR</button>
    </form>

And then we display the QR code in showQR.html template.

<body>

    <div>
        <img class="img-responsive" th:src="@{'data:image/png;base64,'+${textAndQRImage.base64Image}}"/>
    </div>

<h2 th:text=${textAndQRImage.text}></h2>
</body>

Download the complete code for this here: simple-qr code. Live demo on: simple-qr live.

]]>
juan sedano
Plain Thymeleaf2023-04-17T06:00:00+00:002023-04-17T06:00:00+00:00https://jsedano.dev/java/thymeleaf/2023/04/17/plain-thymeleafThymeleaf is an HTML (and more) template engine for Java. This is the core in action with nothing else.

You can find the complete code for this here: only-thymeleaf.

All of this is just putting into a project what has being posted in this stackoverflow answer which in turn was found on this comment on github.

We begin by getting only the core jar for Thymeleaf (the latest one at the time this post was written).

pom.xml

<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf</artifactId>
  <version>3.1.1.RELEASE</version>
</dependency>

Then we create our template inside resources on a directory apptly named templates.

src/main/resources/templates/index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Thymeleaf hello world</title>
</head>
<body>

<p>First name: <span th:text="${first_name}?: '(no first name specified)'"/>.</p>
<p>Last name: <span th:text="${last_name}?: '(no last name specified)'"/>.</p>

</body>
</html>

Inside the span tag we have th which is how all data attributes starts on Thymeleaf, you can see that it’s declared as a namespace definition above on the html tag. We are also using a variable expression ${} with an Elvis operator ?: which is an special operator that only returns it’s value when the evaluated expression returns null, which means if first_name is null then (no first name specified) will be returned.

Now to bring it all together: src/main/java/dev/jsedano/examples/onlythymeleaf/Main.java

var resolver = new ClassLoaderTemplateResolver();
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setPrefix("/templates/");
resolver.setSuffix(".html");

Since we are not using Spring or nothing to helps us with dependency injection we will create objects the traditional way, setting up the prefix for where the templates will be stored and the suffix for them.

var context = new Context();
if (args.length != 0) {
  context.setVariable("first_name", args[0]);
  if (args.length > 1) {
    context.setVariable("last_name", args[1]);
  }
}

This will be the context which will hold the objects that Thymeleaf will use to generate the html.

var templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(resolver);

var result = templateEngine.process("index", context);
System.out.println(result);

Here we create a TemplateEngine object and pass the resolver, then we call process on the templateEngine object with the name of the template and the context we created above.

We can create our fat jar running mvn verify and then call it with java -jar ./target/only-thymeleaf-1.0-jar-with-dependencies.jar to print the result of the template processing, if we send variables when we executed we can see how they get replace:

only-thymeleaf % java -jar ./target/only-thyme  leaf-1.0-jar-with-dependencies.jar
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Thymeleaf hello world</title>
</head>
<body>

<p>First name: <span>(no first name specified)</span>.</p>
<p>Last name: <span>(no last name specified)</span>.</p>


</body>
</html>

only-thymeleaf % java -jar ./target/only-thymeleaf-1.0-jar-with-dependencies.jar juan sedano
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Thymeleaf hello world</title>
</head>
<body>

<p>First name: <span>juan</span>.</p>
<p>Last name: <span>sedano</span>.</p>


</body>
</html>

For more information on Thymeleaf you can go directly to the thymeleaf docs.

Download the complete code for this here: only-thymeleaf.

]]>
juan sedano
Lissajous curve Java2022-10-28T06:00:00+00:002022-10-28T06:00:00+00:00https://jsedano.dev/java/2022/10/28/lissajous-curve-javaJust a Lissajous curve on Java displayed on a JFrame.

You can find the complete code for this here: Lissajous.java.

First of all, the code is a complete rip-off from The Go Programming Language book, specifically from this code from chapter 1.

I won’t even pretend to understand the maths on this one, so lets just dive into the code, first we initialize our window:

int size = 100;
JFrame frame = new JFrame("Lissajous");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(2*size+1, 2*size+1));
frame.add(panel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);

With that we have a non resizable JFrame on the middle of the screen, that terminates the program when closed which contains a JPanel where we can draw, in order to do so we only need the Graphics from the JPanel:

Graphics g = panel.getGraphics();

Then we start shamelessly translating the Go code from the link above to Java:

double cycles = 5;
double angularResolution = 0.001;
long delay = 80;
int frames = 64;
for(;;){
    double frequency = Math.random() * 3.0;
    float phase = 0.0f;
    for( int i = 0; i < frames; i++) {
        g.setColor(Color.BLACK);
        g.fillRect(0,0, panel.getWidth(), panel.getHeight());
        g.setColor(Color.GREEN);
        for(double t = 0.0; t < cycles*2*Math.PI; t+= angularResolution){
            double x = Math.sin(t);
            double y = Math.sin(t * frequency + phase);
            g.drawRect( (size + (int)(x*size+0.5)), (size + (int)(y*size+0.5)),1,1);
        }
        phase += 0.1;
        Thread.sleep(delay);
    }
}

Since its a single file, if we have Java 11 or above we can run it without compiling with:

java Lissajous.java

And we should see this:

lissajous-curve-java


Download the complete code for this here: Lissajous.java.

]]>
juan sedano
Java Redis pub/sub example with Jedis2022-09-19T06:00:00+00:002022-09-19T06:00:00+00:00https://jsedano.dev/java,/redis/2022/09/19/java-redis-pub-sub-exampleThis is a Redis pub/sub example written in Java using Jedis.

Prerequisites

Libraries used

We are only using jedis in order to keep the example simple.

Redis Commands used

subscribe

this is used in order to subscribe to one or more channels:

subscribe channel1 channel2... channelN

unsubscribe

unsubscribe current client to one or more channels:

unsubscribe channel1 channel2... channelN

psubscribe

instead of subscribing to a channel, this allows you to subscribe to one of more patterns:

psubscribe pattern1 pattern2... patternN

for example if you subscribe to foo* it means that you will get the messages meant for all the channels that start with foo.

punsubscribe

unsubscribe from one or more patterns:

punsubscribe pattern1 pattern2... patternN

publish

publish sends a message to connected clients, returns the number of clients that got the message.

publish aChannel 'some message'

ping

sends a ping from a client to the server, optionally you can send a message and the ping will echo it.

ping

or

ping a message

Code walkthrough

We need to extend JedisPubSub in order to give our client functionality.

import redis.clients.jedis.JedisPubSub;

public class LogPubSub extends JedisPubSub {

To keep this example simple we are only going to add very basic functionality, in order to know which client is the one that got the message we are adding a name field.

  private String name;

  public LogPubSub(String name) {
    this.name = name;
  }

For subscribe, unsubscribe, psubscribe, punsubscribe and pong (which is the one that a successful ping triggers) we only print the information:

  public void onSubscribe(String channel, int subscribedChannels) {
    System.out.printf(
        "name: %s method: %s channel: %s subscribedChannels: %d\n",
        name, "onSubscribe", channel, subscribedChannels);
  }

  public void onUnsubscribe(String channel, int subscribedChannels) {
    System.out.printf(
        "name: %s method: %s channel: %s subscribedChannels: %d\n",
        name, "onUnsubscribe", channel, subscribedChannels);
  }

  public void onPUnsubscribe(String pattern, int subscribedChannels) {
    System.out.printf(
        "name: %s method: %s patten: %s subscribedChannels: %d\n",
        name, "onPUnsubscribe", pattern, subscribedChannels);
  }

  public void onPSubscribe(String pattern, int subscribedChannels) {
    System.out.printf(
        "name: %s method: %s patten: %s subscribedChannels: %d\n",
        name, "onPSubscribe", pattern, subscribedChannels);
  }

  public void onPong(String message) {
    System.out.printf("name: %s method: %s message: %s\n", name, "onPong", message);
  }
}

When receiving a message in the client apart from printing the information if the message is a ping then we will do a ping. If receiving the String “exit” we will unsubscribe from that channel or pattern (in the case of client subscribed using psubscribe).

  public void onMessage(String channel, String message) {
    System.out.printf(
        "name: %s method: %s channel: %s message: %s\n", name, "onMessage", channel, message);
    switch (message) {
      case "ping":
        this.ping();
        break;
      case "exit":
        this.unsubscribe(channel);
        break;
      default:
        if (message.indexOf("ping") == 0 && message.indexOf(" ") == 4) {
          this.ping(message.substring(5));
        }
    }
  }

  public void onPMessage(String pattern, String channel, String message) {
    System.out.printf(
        "name: %s method: %s pattern: %s channel: %s message: %s\n",
        name, "onPMessage", pattern, channel, message);
    switch (message) {
      case "ping":
        this.ping();
        break;
      case "exit":
        this.punsubscribe(pattern);
        break;
      default:
        if (message.indexOf("ping") == 0 && message.indexOf(" ") == 4) {
          this.ping(message.substring(5));
        }
    }
  }

Then we only need to make a JedisPooled connection and used it to subscribe to a channel or pattern:

JedisPooled jedis = new JedisPooled("localhost", 6379);
ExecutorService executor = Executors.newFixedThreadPool(4);

executor.execute(() -> jedis.subscribe(new LogPubSub("onlyOne"), "dev.one"));
executor.execute(() -> jedis.subscribe(new LogPubSub("oneAndTwo"), "dev.one", "dev.two"));
executor.execute(() -> jedis.psubscribe(new LogPubSub("pattern"), "dev.*"));

We need to run the subscribe and psubscribe on a thread since those are blocking operations.

In this example we are creating three clients, which we will identify as “onlyOne”, “oneAndTwo” and “pattern”, this doesn’t mean anything to redis, but it will be easier for us to keep track of whats happening.

  • “onlyOne” is subscribed to channel “dev.one”.
  • “oneAndTwo” is subscribed to channels “dev.one” and “dev.two”.
  • “pattern” is subscribed to the pattern “dev.*”.

With this we could send messages using publish on our RedisInsight CLI which should be running on http://localhost:8001/redis-stack/browser if we installed the redis-stack.

But we will also send messages using jedis.

String message = "";
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
  do {
    message = br.readLine();
    int firstSpace = message.indexOf(' ');
    if (firstSpace > 1) {
      jedis.publish(message.substring(0, firstSpace), message.substring(firstSpace + 1));
    }
  } while (!"close".equals(message));
  jedis.close();
  System.exit(0);
} catch (IOException e) {
  throw new RuntimeException(e);
}

For building the code run mvn package and a far jar will be generated on target and then you can run it like so java -jar RedisPubSub-1.0.jar.

Example run:

... target % java -jar RedisPubSub-1.0.jar
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
name: pattern method: onPSubscribe patten: dev.* subscribedChannels: 1
name: oneAndTwo method: onSubscribe channel: dev.one subscribedChannels: 1
name: oneAndTwo method: onSubscribe channel: dev.two subscribedChannels: 2
dev.one hello
name: pattern method: onPMessage pattern: dev.* channel: dev.one message: hello
name: oneAndTwo method: onMessage channel: dev.one message: hello
dev.five hello to you
name: pattern method: onPMessage pattern: dev.* channel: dev.five message: hello to you
dev.two also to you
name: pattern method: onPMessage pattern: dev.* channel: dev.two message: also to you
name: oneAndTwo method: onMessage channel: dev.two message: also to you
dev.six exit
name: pattern method: onPMessage pattern: dev.* channel: dev.six message: exit
name: pattern method: onPUnsubscribe patten: dev.* subscribedChannels: 0
dev.two exit
name: oneAndTwo method: onMessage channel: dev.two message: exit
name: oneAndTwo method: onUnsubscribe channel: dev.two subscribedChannels: 1
dev.one ping say my name
name: oneAndTwo method: onMessage channel: dev.one message: ping say my name
name: oneAndTwo method: onPong message: say my name
dev.two are you alive?
dev.five no one is listening here
dev.one this one is alive
name: oneAndTwo method: onMessage channel: dev.one message: this one is alive
dev.one exit
name: oneAndTwo method: onMessage channel: dev.one message: exit
name: oneAndTwo method: onUnsubscribe channel: dev.one subscribedChannels: 0
dev.one not anymore
close
... target %

Download the complete code for this here: Java Redis pub/sub example.

]]>
juan sedano
Redis 20222022-09-17T06:00:00+00:002022-09-17T06:00:00+00:00https://jsedano.dev/redis/2022/09/17/redis-2022What is Redis (Remote Dictionary Server) on 2022. What can we do with it. How to scale. How to run it on the cloud.

What is Redis?

Redis is a key value store, just like a hash table. It can be used in-memory as cache and data will not be persisted or it can persist the data and be use as data storage. Keys can have a length to up to 512 MB.

It can also be used as a message queue / message broker.

Supported data types

Redis supports several data types

Type Max Size Description
Strings 512 MB Bytes, text, serialized objects, binary arrays
Lists 2^32 - 1 (4,294,967,295) elements. Linked list of Redis Strings
Sets 2^32 - 1 (4,294,967,295) members. Unordered unique Redis Strings
Sorted Sets Not specified Every String has also an integer weight that you must set up
Hashes 4,294,967,295 (2^32 - 1) field-value pairs Hash table
Streams Not specified Used to track real time events and allows consumers and consumer groups to read them

Special use cases types

Allows to store coordinates and perform operations such as finding the closest one.

Not gonna even try to summarize this one, read this instead.

Use a String like a bit vector, allows performing bitwise operations.

Allows storing, atomic read, write and read operations for 1 bit unsigned integers to 63 signed bit integers.

Additional support

RedisJSON

Adds facilities to store json documents and adds operations to be able to access / update fields using JSONPath.

RedisGraph

A graph database.

RedisTimeSeries

Module that adds a time series data structure to Redis, allowing querying by start / end time.

RedisBloom

Probabilistic data structures.

RedisInsight

Visual support that helps optimizing your stuff on Redis.

Message queues with Redis Pub/Sub

We can use Redis to create channels, send messages to the channels and have subscribers that recive the message.

Redis on the cloud

redis cloud

We can use a hosted service using the offer from Redis on Redis Cloud.

Or you can install it following guides detailed here.

aws

AWS only supports Redis as an in memmory database, but you could try to install it on a service like EC2 and put a separate storage to persist.

gcp

Google cloud platform currently does not suppert persisting the data out of the box.

azure

Apparently you can persist using out of the box redis services on azure, but they dont recomend it.

Scalabity

You can scale horizontally using Redis Cluster where you have a master that replicates the information between replicas, but it doesn’t guarantees that you are not going to lose data, if you are unlucky that a replica is randomly selected as master and then it goes down before propagating the changes, it can lose data, unless you configure it so that the master has to acknowledge having replicated the information, but then you have to accept a hit on your performance.

Security

Redis recomends that redis is only used on trusted environments where only trusted clients can access it.

]]>
juan sedano
A custom annotation to apply currying in Java2022-06-26T06:00:00+00:002022-06-26T06:00:00+00:00https://jsedano.dev/java/2022/06/26/a-custom-annotation-to-apply-currying-in-javaI created a custom annotation in order to apply currying to a method or constructor.

You can find the complete code for this here: curry.

For more information on currying check this post and for a background on annotations in Java check this one.

First we create the annotation:

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Curry {}

We only need the annotation to be processed and then discarded (we don’t need to have it available at run time or recorded on the .class) so we use @Retention(RetentionPolicy.SOURCE).

This annotation will only be used on methods and constructors so we set those as the Target on @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}).

Then we create a processor for the annotation:

@SupportedAnnotationTypes("dev.jsedano.curry.annotation.Curry")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(Processor.class)
public class CurryProcessor extends AbstractProcessor {

Using @SupportedAnnotationTypes("dev.jsedano.curry.annotation.Curry") we say that this processor will only look for that particular annotation.

@SupportedSourceVersion(SourceVersion.RELEASE_17) here we are saying the Java version supported.

The last one is pretty interesting, @AutoService(Processor.class) is from a Google library called auto-service. In order for the Java compiler to use a processor the class needs to be declared inside the jar on the META-INF/services directory on the javax.annotation.processing.Processor file, the auto-service library does that for you.

Then we need to implement the process method on out custom processor.

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

Inside our class we get the processingEnv object that provides us with functionality such as getMessager() that we use to print a warning message on compile time when the @Curry annotation is used on a method with 1 or more than 10 parameters:

otherMethods.stream()
    .forEach(
        e ->
            processingEnv
                .getMessager()
                .printMessage(
                    Diagnostic.Kind.MANDATORY_WARNING,
                    "incorrect number of parameters, allowed only between 2 and 1O, will not generate code for this one",
                    e));

We also have this one getFiler() which allows us to create Java source files:

JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(builderClassName);

On the tests module of the project we declare some methods with the @Curry annotation, for example this constructor:

@Curry
public AnnotatedClass(
    boolean aBoolean, List<String> aStringList, int aNumber, char aChar, float aFloat) {
  this.aBoolean = aBoolean;
  this.aStringList = aStringList;
  this.aNumber = aNumber;
  this.aChar = aChar;
  this.aFloat = aFloat;
}

After running mvn clean verify on the parent module we can see the autogenerated code under target/generated-sources/annotations/dev.jsedano.curry.tests:

public static java.util.function.Function<java.lang.Boolean,java.util.function.Function<java.util.List<java.lang.String>,java.util.function.Function<java.lang.Integer,java.util.function.Function<java.lang.Character,java.util.function.Function<java.lang.Float,dev.jsedano.curry.tests.AnnotatedClass>>>>> pentaConstructor(dev.jsedano.curry.util.function.PentaFunction<java.lang.Boolean,java.util.List<java.lang.String>,java.lang.Integer,java.lang.Character,java.lang.Float,dev.jsedano.curry.tests.AnnotatedClass> function) {
    return v0->v1->v2->v3->v4-> function.apply(v0,v1,v2,v3,v4);
}

It is not pretty looking, but we can use it to then curry the five parameter constructor of the example class:

var pentaConstructor = AnnotatedClassCurryer.pentaConstructor(AnnotatedClass::new);

You can see another example here, but if you want to compile it you need to do mvn clean install on the curryer module of curry.

@Curry
public static String wget(
    int connectionTimeout,
    int readTimeout,
    boolean followRedirects,
    String requestMethod,
    String address) {
  try {
    URL url = new URL(address);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod(requestMethod);
    con.setConnectTimeout(connectionTimeout);
    con.setReadTimeout(readTimeout);
    con.setInstanceFollowRedirects(followRedirects);
    BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String inputLine;
    StringBuffer content = new StringBuffer();
    while ((inputLine = in.readLine()) != null) {
      content.append(inputLine);
    }
    in.close();
    return address + " " + content.toString();
  } catch (Exception e) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    e.printStackTrace(pw);
    String stackTrace = sw.toString();
    return address + " " + stackTrace.substring(0, stackTrace.indexOf("\n"));
  }
}

Then we can set the values we need in a curried way and use it:

public static void main(String[] args) {
  var get =
      WgetVersion2Curryer.wget(WgetVersion2::wget)
          .apply(100)
          .apply(100)
          .apply(false)
          .apply("GET");

  List.of(
          "https://www.google.com",
          "https://www.wikipedia.org",
          "asdf",
          "https://docs.oracle.com/javase/10/docs/api/java/net/package-summary.html",
          "https://jsedano.dev",
          "https://raw.githubusercontent.com/center-key/clabe-validator/main/clabe.ts")
      .parallelStream()
      .map(get)
      .forEach(System.out::println);
}

Download the complete code from this post here: curry.

]]>
juan sedano
Java @Annotations2022-06-18T06:00:00+00:002022-06-18T06:00:00+00:00https://jsedano.dev/java/2022/06/18/java-annotationsIf you have been using Java for about a week (probably even less) chances are you have already seen some annotations. Let’s review some stuff about them.

As explained on https://docs.oracle.com/javase/tutorial/java/annotations/ we can use annotations to:

  • Give information to the compiler: so we can detect errors or even suppress warnings.
  • Compile-time and deployment-time processing: we can generate code, xml files and so on.
  • Runtime processing: some annotations can be reviewed at runtime (using reflection).

Annotations can be used anywhere you use a type.

One interesting fact is that annotations can potentially generate code, but they can not modify it. If you use tools like lombok you know that they actually modify the code, but they usually achieve this by accessing internal libraries.

Annotations are defined with the @interface keyword like so:

public @interface Version {
  int mayor();
  int minor();
}

They can receive any primitive types, enums, other annotations and arrays of those previously mentioned. Let’s define an enum:

public enum Usage {
  UTILITY,
  DTO,
  DAO,
  SERVICE
}

Then let’s create another annotation:

public @interface Info {
  String[] authors();
  Usage usage();
  Version version();
}

Now we use it:

@Info(
    authors = {"jsedano", "weirderror"},
    usage = Usage.UTILITY,
    version = @Version(mayor = 1, minor = 0))
public class VeryUtil {}

You can specify if the annotation needs to be retained by the virtual machine at run time or not; or even if they are to be discarded by the compiler. This is achieved by using a meta-annotation, meta-annotations are annotations that are applied to another annotations.

You can also define where the annotation can be used, for example in methods, in constructors and so on.

Let’s look at how the @Override annotation is defined (@Override is a predefined annotation that is use to mark methods that are using method overriding):

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

As you can see the meta-annotation @Target is used to say that this particular annotation can only be used above a method declaration and the @Retention annotation is saying that this annotation will not be recorded in the class file and will not be available at runtime.

In order to actually define functionality for an annotation type we need to implement an AbstractProcessor.

]]>
juan sedano
Currying in Java2022-06-13T06:00:00+00:002022-06-13T06:00:00+00:00https://jsedano.dev/java/2022/06/13/currying-in-javaLet’s see some examples of how to achieve currying in Java.

You can find the complete code for this here: curry_example.jsh.

Currying is taking a function with n parameters and returning a function with one parameter that returns a function with one parameter until you reach the n parameters of the original function and then you get the result.

The following method gets the curried version of a method with the signature:

int methodName(int a, int b)

And returns the curried version:

public static Function<Integer, Function<Integer, Integer>> toCurry(
    BiFunction<Integer, Integer, Integer> function) {
  return v -> v1 -> function.apply(v, v1);
}

Then we can use it to get curried versions of such methods:

var curriedAdd = toCurry(Math::addExact);
var curriedMultiply = toCurry(Math::multiplyExact);

And use them like this:

System.out.format("curriedAdd(2)(10): %d\n",curriedAdd.apply(2).apply(10));
System.out.format("curriedMultiply(2)(10): %d\n",curriedMultiply.apply(2).apply(10));

In the following example we use the curried versions to first add 1 and then multiply by 2 all the elements of a stream

var add1 = toCurry(Math::addExact).apply(1);
var multiplyBy2 = toCurry(Math::multiplyExact).apply(2);
List.of(0, 1, 2, 3, 4).stream().map(add1).map(multiplyBy2).forEach(System.out::println);

We can use currying as a form of partial application, imagine we have the following method:

public static String wget(
    int connectionTimeout,
    int readTimeout,
    boolean followRedirects,
    String requestMethod,
    String address) {
  try {
    URL url = new URL(address);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod(requestMethod);
    con.setConnectTimeout(connectionTimeout);
    con.setReadTimeout(readTimeout);
    con.setInstanceFollowRedirects(followRedirects);
    return address + " " + con.getResponseCode();
  } catch (Exception e) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    e.printStackTrace(pw);
    String stackTrace = sw.toString();
    return address + " " + stackTrace.substring(0, stackTrace.indexOf("\n"));
  }
}

This method returns the http status or part of the exception if any was thrown.

If we use it like that we would have to be setting all the parameters everytime we want to use the function, but if we have a curried version:

public static Function<Integer, Function<Boolean, Function<String, Function<String, String>>>>
    cwget(int v) {
  return v1 -> v2 -> v3 -> v4 -> wget(v, v1, v2, v3, v4);
}

We could then set the parameters we have:

var get = cwget(100).apply(100).apply(false).apply("GET");

And then just fill the renaming parameter when using the function:

List.of(
        "https://www.google.com",
        "https://www.wikipedia.org",
        "asdf",
        "https://docs.oracle.com/javase/10/docs/api/java/net/package-summary.html",
        "https://jsedano.dev",
        "https://raw.githubusercontent.com/center-key/clabe-validator/main/clabe.ts")
    .parallelStream()
    .map(get)
    .forEach(System.out::println);

Download the complete code from this post here: curry_example.jsh.

]]>
juan sedano
Remove duplicates in unordered array with Java using streams2022-05-28T06:00:00+00:002022-05-28T06:00:00+00:00https://jsedano.dev/java/2022/05/28/remove-duplicates-in-unordered-arrayHeres how to remove duplicates from an unordered primitive int array on Java using streams.

You can find the complete code for this here: remove_dupes_unordered_the_smart_way.jsh.

Consider the following straight forward problem, you receive a primitive int array and you need to return a new array only containing the unique elements.

Because we are using streams since 2014 and we know that a Set does not accept duplicates, we only need to collect the array into a set and back into an array.

int[] removeDupes(int arr[]) {
    return Arrays.stream(arr)
        .boxed()
        .collect(Collectors.toSet()).stream()
        .mapToInt(Integer::intValue).toArray();
}

The boxed method just returns an Integer stream instead of a primitive one.

Download the complete code from this post here: remove_dupes_unordered_the_smart_way.jsh.

]]>
juan sedano
Remove duplicates in ordered array Java2021-07-05T06:00:00+00:002021-07-05T06:00:00+00:00https://jsedano.dev/java/2021/07/05/remove-duplicates-in-ordered-arrayHeres how to remove duplicates from an ordered primitive int array on Java.

You can find the complete code for this here: remove_dupes.jsh.

Consider the following problem, you have to remove the duplicates from an ordered integer array in place. Since you cant actually change the length of a primitive array in java without declaring a new one, you will return the new length the array would have without the duplicates.

In order to solve this in O(n) time and O(1) space we are going to use a two pointer technique. We will have j that will increase by one in every iteration and i which will increase only if its different from the value which j points to, ignoring every duplicate found.

This doesn’t account for a null, or less than a lenght 2 array (in which case we could start j at 0).

The pre-increment could be less readable but just remember that ++variable means we are increasing first and then using the variable.

int removeDupes(int arr[]) {
    int i = 0;
    for(int j = 1; j < arr.length; j++) {
        if(arr[i] != arr[j]) {
            arr[++i] = arr[j];
        }
    }
    return ++i;
}

Download the complete code from this post here: remove_dupes.jsh.

]]>
juan sedano