2

So my Programming professor wants me to write a Kingdom class with a variable name that's at least 12 characters long. Normally one would just implement this class with a String name variable and an error message if the invariant of 12 characters min is broken, something like this in Java:

import java.lang.annotation.AnnotationTypeMismatchException;
public class Kingdom {

    private String name;
    public String getName(){return name;}

    public Kingdom(String name) {
        if (name.length() < 12){
            throw new IllegalArgumentException("name must have at least 12 characters");
        }
        this.name = name;
    }

}

or that in Kotlin:

import java.lang.IllegalArgumentException

class KingdomName (name: String) {
    public val name: String = if (name.length >= 12) name else throw IllegalArgumentException("name must have at least 12 characters")
}

But I wanna know if there is a more elegant path in which the "must have at least 12 characters" invariant can be defined right in the variable name itself, forcing my professor to input at least 12 characters for the name like we all are forced to assign integers from -2,147,483,648 to 2,147,483,647 to a variable from type int/Int.

Now I thought about making my name a char[] array and allowing only char arrays longer or equal to 12 in the constructor, something like this in fake-Java:

public class Kingdom {

    private char[] name;

    public Kingdom(char[<=12] name) {   //this line cannot exist in real Java
        this.name = name;
    }
}

But is there a way?

I also consider inventing a new type called KingdomName that is identical to a char[] array but must always have at least 12 elements, but again, how do I do that?

Thomas Fritz
  • 140
  • 2
  • 10
  • 1
    Throwing an exception is likely your best bet. Even if you accepted a `char[]`, someone could still pass an array with less than 12 elements. – Logan May 05 '19 at 21:15
  • You may want to look at [Hibernate Validator](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#chapter-bean-constraints). I've linked to the section that'll give you exactly how to implement it. – priyank-sriv May 05 '19 at 21:23
  • Thanks for the suggestion @Sindbad90, I'll definitely look into the Hibernate Validator the next time I'll face this problem in the context of a serious project. But for this assignment, external libraries downloaded from the internet are not an option. I did however find out another secure yet not very elegant way to achieve the minimum name length of 12 inside the constructor by letting my professor type in the chars individually. The code is about 200 letters too long to post it as a comment though – Thomas Fritz May 05 '19 at 22:40

3 Answers3

2

One of my best ideas would be to just move the check from constructor to a separated method with name describing the logic inside. Something like this:

private void validateHasAtLeast12chars(String toValidate)

Putting a logic into named method is always good practice, this is both elegant and easy to follow. If you have a logic that could be named then it is always elegant if it is in its own method with that name.

Krzysztof Cichocki
  • 6,294
  • 1
  • 16
  • 32
0

OK so I've found out a strategy that works for my specific problem, establishing a minimum character count for whenever an instance of a Kingdom shall be created, and it goes like this in Java:


public abstract class CustomTools {
    public static char[] combineCharArrays(char[] array1, char[] array2){
        // combines two char[] arrays into one with the combined length and returns the result
        // no need to get too specific ;)
    }
}
public class Kingdom {

        private char[] name;
        public char[] getName(){return name;}

        public Kingdom(char nameChar1, char nameChar2, char nameChar3, char nameChar4, char nameChar5, char nameChar6, char nameChar7,
                       char nameChar8, char nameChar9, char nameChar10, char nameChar11, char nameChar12, char... restName) { //

            char [] name = CustomTools.combineCharArrays(new char[] {nameChar1, nameChar2, nameChar3, nameChar4, nameChar5, nameChar6, nameChar7,
                    nameChar8, nameChar9, nameChar10, nameChar11, nameChar12}, restName);

            this.name = name;
    }
}

However, this implementation is tedious to work with (instead of one word, everyone using the Kingdom class must put in at least 12 single characters, divided by commata) and therefore not very elegant, defying my initial goal. I also imagine the concept behind this code to not work or be inappropriate for a variety of use-cases.

So a real answer to this question has yet to be found.

Thomas Fritz
  • 140
  • 2
  • 10
  • 2
    This is the only answer (so far) which enforces the 12-character limit **at compile time**, which is what I think the questioner was aiming for. Though, as you say, it's very specific and not at all practical, and I really wouldn't want to see it in production code... – gidds May 06 '19 at 08:44
0

There’s no way to do what you want, which is bind a constraint with a message to a field, in "raw" java, but you can use annotations.

Note that when using annotations you don’t avoid any code, you just move it somewhere else.

class Kingdom {
    @MinLength(12)
    private String name;

    ...
}

You would then need to create the MinLength annotation class and implement the behaviour you want, using reflection to find out the name of the field so annotated to use in the message.

We call this type of implementation over engineering, but it would work.

Bohemian
  • 412,405
  • 93
  • 575
  • 722