3

[Context: new to Java, 4 months tops; old hand at C++.]

I'm working on a library that requires an array of a fixed size ("fixed string") in many places. I'm trying to use Dependency Injection (q.v.) for this particular problem, so I would like something of the form:

class Foo 
{
    private Bar injectedBar;
    private char[] injectedFixedString;

    Foo(Bar injectedBar, /* what can go here? */ char[5] injectedFixedString);
    { /* initializing code goes here /* }
}

Simple is required -- this is going into an auto-generated communications protocol. I have zero control of the protocol and database it's being derived from; I will have hundreds, if not thousands, of these instances in the final code. So, given all that:

Is my only alternative to the C++:

char injectedFixedString[5];

to create a custom class? Something like:

class FixedBarString {
    /* could also set this in the constructor, but this complicates code generation a tad */
    public static integer STRING_SIZE = 5; /* string size */
    char[] fixedString = new char[STRING_SIZE];

    FixedBarString(char[] string) throws RuntimeException {
      /* check the string here; throw an exception if it's the wrong size.
         I don't like constructors that throw however. */
    }

    public void setString(char[] string) throws RuntimeException {
      /* check the string here */
    }

    public char[] getString() {
      /* this isn't actually safe, aka immutable, without returning clone */
    }

    public char[] createBlankString() {
      return new char[STRING_SIZE];
    }
}

Thanks. (My apologies if this is too much code).

dogbane
  • 266,786
  • 75
  • 396
  • 414
John Price
  • 556
  • 1
  • 6
  • 18
  • 1
    Wrote an answer then realised I don't actually follow what you're trying to do here. What would Foo(Bar injectedBar, /* what can go here? */ char[5] injectedFixedString); do if you passed a string with 6 characters? If I knew how C++ handled that I would probably be able to help you better. – Endophage Jan 21 '11 at 17:01
  • The OP is looking for an alternative to C++'s fixed sized arrays e.g. in C++ the following is method declaration is valid: `myMethod(char myarray[5])` – dogbane Jan 21 '11 at 17:06
  • @dogbane: and what does that declaration DO? – Michael Borgwardt Jan 21 '11 at 17:14
  • @michael-borgwardt If you call the method with a `char array[3]`, the compiler will tell you that it is not legal. The compiler is capable of detecting type mismatches when you use statically sized arrays. – dogbane Jan 21 '11 at 17:28
  • This is for a library for other programmers for using a bit-packed protocol. In this case I would like to clearly show that a given field is, for example "3 characters", to the caller while simultaneously preventing any "incorrect" call in the first place. – John Price Jan 21 '11 at 19:16
  • A little more detail may be in order. To construct a message of type "Foo", I would like the caller to create sub-message "Bar" and character string of length = 5. The constructor for "Foo" should be as "obvious and error resistant" as feasible to avoid "error tag" on the part of the calling programmer. (See also dogbane's comment above). – John Price Jan 21 '11 at 19:50

4 Answers4

2

There is indeed no way to do what you want with a statically guaranteed length, unless you are prepared to have a new class for every length: FixedBarString4, FixedBarString5, etc. (It is possible to create a class for single linked list of chars which uses generics to encode the length. But I doubt you would like to use that in your real world scenario.

jmg
  • 7,308
  • 1
  • 18
  • 22
  • 1
    Thanks, it looks like this is the way I'll be forced to go. My brief Google Search didn't turn up anything promising on Bean Validation & Android. – John Price Jan 21 '11 at 19:55
2

I'm not 100% certain what you want to achieve. Prevent the constructor from being called with an array of a different size? At compile time? Why is a check&throw at runtime not an acceptable solution?

If your dependency injection framework supports the new bean validation standard, then this would get you the checking during injection:

Foo(Bar injectedBar, @Size(min=5,max=5) char[] injectedFixedString)
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • Target platform is android (1.6, but we will be upgrading to 2.2) and I know even less about Android than I do Java. _If_ it's supported, that would work fine. – John Price Jan 21 '11 at 19:18
1

Can't you use java.lang.String in the java program, and only convert it to an array when/if needed. Using toCharArray(), and limiting the string before that (using StringUtils.right(str, 5) from commons-lang, for example)

Or you can throw an IllegalArgumentException when a string with a length more than 5 is passed to the method.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • In this particular case, I need for the calling programmer to know that the library expects _exactly_ "N" characters; taking a subset causes too many problems with this particular protocol. This may be, for example, a unique ID (I'm not so worried about comment fields). For example -- if the field is a 6 digit ID, would "12345678" really be ID "123456", "234567" or "345678"? How would the caller debug this? Not enough characters pretty much guarantees that the caller will not get the results he/she wanted in many cases. In the ID example, "123" will not match up to any six digit ID. – John Price Jan 21 '11 at 19:29
0

You can have

Foo(Bar injectedBar, char[] injectedFixedString)

and call it with

new Foo(injectedBar, new char[5])

or

Foo(Bar injectedBar, fixedStringLength)
new Foo(injectedBar, 5)

its also worth noting that char is 2 bytes, not one. does your protocol assume 16-bit characters or 8-bit.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • @peter-lawrey yes, but in the constructor you will still have to check that the array being passed in is of length 5. You can't declare `Foo(Bar injectedBar, char injectedFixedString[5])` as in C++. – dogbane Jan 21 '11 at 17:08
  • The actual value I need is 7-bit ASCII, but according to the net (caveat emptor) the first 128 values of Unicode (0 - 127) are the ASCII set. I'm planning on masking the values down from 16-bits to 7-bits. – John Price Jan 21 '11 at 19:30
  • @John, you should use a byte[] which 8-bit. – Peter Lawrey Jan 21 '11 at 20:42
  • Yeah, thanks. It looks like I can use built-in java.io methods to convert byte[] of ASCII using UTF-8 <-> Unicode which was a concern (previous google searches were inconclusive). Since this is a bit-packed protocol (it will only use 7 bits either way) it shouldn't matter; but it's Android, so space is at a premium. – John Price Jan 21 '11 at 21:26