What’s the Difference Between a Login and a Nonlogin Shell?

Table of Contents

This is addressed nicely in the book Unix Power Tools (Oreilly):

When you first log in to a Unix system from a terminal, the system normally starts a login shell. A login shell is typcally the top-level shell in the “tree” of processes that starts with the init process. Many characteristics of processes are passed from parent to child process down this “tree” — especially environment variables, such as the search path. The changes you make in a login shell will affect all the other processes that the top-level shell starts — including any subshells.

So, a login shell is where you do general setup that’s done only the first time you log in — initialize your terminal, set environment variables, and so on. […]

So you could think about a login shell as a shell that is started at startup by the init process (or systemd nowadays). Or as a shell that logs you into the system by your providing a username and a password. A nonlogin shell, by contrast, is a shell that is invoked without logging anybody in.

Is My Current Shell a Login Shell?

There are two ways to check if your current shell is a login shell: First, you can check the output of echo $0: if it starts with a dash (like -bash), it’s a login shell. Be aware, however, that you can start a login shell with bash --login, and echo $0 will output just bash without the leading dash, so this is not a surefire way of find out if you are running a login shell.

Secondly, the Unix StackOverflow offers this way of finding out:

$ shopt -q login_shell && echo login || echo nonlogin

(-q supresses the output of the shopt command.)

The Difference Between Login and Nonlogin That Actually Matters

Practically speaking, the difference between a login shell and a nonlogin shell is in the configuration files that Bash reads when it starts up. In particular, according to man bash:

[…] it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

You can observe this behavior by putting echo commands in /etc/profile, ~/.bash_profile, ~/.bash_login and ~/.profile. Upon invoking bash --login you should see:

echo from /etc/profile
echo from ~/.bash_profile
$

If the shell is a nonlogin shell, Bash reads and executes commands from ~/.bashrc. Since we are starting a nonlogin shell from within a login shell, it will inherit the environment. Sometimes, this will lead to confusion when we inadvertantly get a login shell, and find out that our configuration from ~/.bashrc is not loaded. This is why many people put something like the following in their .bash_profile:

[[ -r ~/.bashrc ]] && source ~/.bashrc

This test whether .bashrc is readable and then sources it.

Why You Sometimes Want a Login Shell

When you switch users using su you will take the environment of the calling user with you. To prevent this, you should use su - which is short for su --login. This acts like a clean login for a new user, so the environment will not be cluttered with values from the calling user. Just as before, a login shell will read /etc/profile and the .bash_profile of the user you are switching to, but not its .bashrc. This post on StackOverflow shows why you might want to prefer to start with a clean environment (spoiler: your $PATH might be “poisened”).

Conclusion

In this article we saw that the main difference between a login and a nonlogin shell are the configuration files that are read upon startup. We then looked at what the benefits are of a login shell over a nonlogin shell.

Encrypt Device With Veracrypt From the Command Line

Table of Contents

You have a drive that you want to encrypt and use in Linux and other OSes. Then Veracrypt, the successor of Truecrypt, is a good choice. The prerequisite for this tutorial is that you already have created a partition on a drive. See my previous blog post on how to accomplish that. Creating a volume on a partition with data on it will permanently destroy that data, so make sure you are encrypting the correct partition (fdisk -l is your friend).

Encrypt a volume interactively from the command line using Veracrypt…

(The # sign at the beginning of the code examples indicates that the command should be executed as root. You can either use su - or sudo to accomplish this.)

# veracrypt -t --quick -c /dev/sdXX

-t is short for --text (meaning you don’t want the GUI) and should always be used first after the command name. The --quick option is explained in the docs:

If unchecked, each sector of the new volume will be formatted. This means that the new volume will be entirely filled with random data. Quick format is much faster but may be less secure because until the whole volume has been filled with files, it may be possible to tell how much data it contains (if the space was not filled with random data beforehand). If you are not sure whether to enable or disable Quick Format, we recommend that you leave this option unchecked. Note that Quick Format can only be enabled when encrypting partitions/devices.

So, using --quick is less secure, but not specifying it could take (a lot) longer, especially on traditional hard drives (we’re talking hours for 500GB).

Finally, the -c or --create command allows us to specify on which partition we want to create a veracrypt volume. Make sure you change the /dev/sdXX from the example above to the appropriate output of fdisk -l (for example, /dev/sdc1).

This command will interactively guide us to create a new volume:

Volume type:
 1) Normal
 2) Hidden
Select [1]: 1

Encryption Algorithm:
 1) AES
 2) Serpent
 3) Twofish
 4) Camellia
 5) Kuznyechik
 6) AES(Twofish)
 7) AES(Twofish(Serpent))
 8) Camellia(Kuznyechik)
 9) Camellia(Serpent)
 10) Kuznyechik(AES)
 11) Kuznyechik(Serpent(Camellia))
 12) Kuznyechik(Twofish)
 13) Serpent(AES)
 14) Serpent(Twofish(AES))
 15) Twofish(Serpent)
Select [1]: 1

Hash algorithm:
 1) SHA-512
 2) Whirlpool
 3) SHA-256
 4) Streebog
Select [1]: 1

Filesystem:
 1) None
 2) FAT
 3) Linux Ext2
 4) Linux Ext3
 5) Linux Ext4
 6) NTFS
 7) exFAT
Select [2]: 6

Enter password:
WARNING: Short passwords are easy to crack using brute force techniques!

We recommend choosing a password consisting of 20 or more characters. Are you sure you want to use a short password? (y=Yes/n=No) [No]: y

Re-enter password:

Enter PIM:

Enter keyfile path [none]:

Please type at least 320 randomly chosen characters and then press Enter:
Characters remaining: 4

Done: 100.000%  Speed: 61.8 GB/s  Left: 0 s

The VeraCrypt volume has been successfully created.

The volume is now created in the partition and is ready to be mounted.

… Or do it all in a one-liner

# veracrypt --text --quick                      \
        --non-interactive                       \
        --create /dev/sdXX                      \
        --volume-type=normal                    \
        --encryption=AES                        \
        --hash=SHA-512                          \
        --filesystem=NTFS                       \
        --password='Un$@f3'

Use --stdin to read the password from the standard in, instead of supplying it directly to the command, which is considered unsecure.

Mounting the volume

# mkdir /tmp/vera
# veracrypt -t /dev/sdXX /tmp/vera

Unmouting the volume

# veracrypt -d /tmp/vera

More info

$ veracrypt -t -h

-h is short for --help and should be self-explanatory.

Make less Options Permanent (or: the Missing .lessrc)

Table of Contents

The missing $HOME/.lessrc

I often wondered how I could make certain options for less permanent, like -I, for example, which will make search case insensitive. In GNU/Linux, preferences are often stored in rc files. For vim we have .vimrc, for Bash .bashrc, etc:

$ find "$HOME" -maxdepth 1 -name '*rc'
./.vimrc
./.idlerc
./.xinitrc
./.lynxrc
./.old_netrc
./.inputrc
./.bashrc
./.rtorrent.rc
./.sqliterc
./.xdvirc

Environment variable LESS

So, it would make sense to expect a .lessrc. But there is none. Instead, we define a environment variable LESS. My .bashrc:

export LESS="IFRSX"

Breakdown:

  • -I: ignore case when searching
  • -F: quit immediately when the entire file fits in one screen (in effect, mimic cat’s behavior)
  • -R: enable colored output (for example, when piping to less from diff --color=always)
  • -S: truncate long lines instead of wrapping them to the next line
  • -X: don’t clear screen on exit

See man 1 less for all options.

Make a Backup With rsync

Table of Contents

We want to make a backup of data, for example to an external hard drive.

The basic command

Assuming we are in someone’s home directory and we want to copy three source directories Music, Documents and Movies to a destination directory /mnt/external-hdd:

$ rsync -a Music Documents Movies /mnt/external-hdd

A word on slashes

Notice that we omit the trailing forward slash / on the source directories. This means the destination will look like:

/mnt/external-hdd
|-- Music
|   |-- a.mp3
|-- Documents
|   |-- b.txt
|-- Movies
|   |-- c.mp4

If we were to add trailing forward slashes, the upper-level source directories would not be copied and the result would look like:

/mnt/external-hdd
|-- a.mp3
|-- b.txt
|-- c.mp4

Read more about slashes in rsync.

The rsync -a command broken down

rsync -a is equal to rsync --archive and is a convenience command. According to the man page, it equals rsync -rlptgoD.

  • -r or --recurse: recursively copy data
  • -l or --links: copy symlinks as symlinks
  • -p or --perms: preserve permissions
  • -t or --times: preserve modifications times
  • -g or --group: preserve the group
  • -o or --owner: preserve owner
  • -D is the same as --devices --specials:
    • --devices: preserve device files
    • --specials: preserve special files

[…] a device file or special file is an interface to a device driver that appears in a file system as if it were an ordinary file

Wikipedia

Device files in Linux are usually found under the /dev directory.

See the overall progress of rsync

By default, rsync will show the progress of the individual files that are being copied. If you want the overall progress, you have to add some flags:

$ rsync -a --info=progress2 --no-i-r src dst

--info=progress2 shows the total transfer progress. (To see all available options for --info, execute rsync --info=help). --no-i-r is short for --no-inc-recursive and disables incremental recursion, forcing rsync to do a complete scan of of all directories before starting the file transfer. This is needed to get an accurate progress report, otherwise rsync doesn’t know how much work is left.

Human-readable output can be obtained by passing the -h or --human-readable option.

For a discussion of these options, see also this StackOverflow post.

Partition and Format Drive With NTFS

Table of Contents

Say we bought an external hard drive to back up some stuff from a crashed computer. We can use a Live USB to get at the data and put the data on the external hard drive. Because the data needs to be accessible by Windows, we are going to use format the drive with NTFS.

Create partition

Connect the external hard disk to your computer. Use sudo fdisk -l to find the device name. Output should look something like this:

Disk /dev/sdb: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Disk model: CT2000MX500SSD1
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x117d68c1

Device     Boot Start        End    Sectors  Size Id Type
/dev/sdb1        2048 3907029167 3907027120  1.8T 83 Linux

As can been seen above, the name of the device is /dev/sdb. We use to name to run fdisk:

$ sudo fdisk /dev/sdb

Notice how we use the name of the device, and not the name of the partition (so /dev/sdb without any numbers attached at the end).

After entering the command above, an interactive menu will be facing you. Type a letter and press Enter to confirm. Changes will only be applied when you type w, so if you make a mistake, just stay calm and press q and you will exit fdisk with your pending changes discarded.

  • Delete all your existing partitions by pressing d. Depending on the amount of partitions, you might have to repeat this several times. If you want to check the current partition table, press p.
  • After all old partitions are deleted, add a new partition by pressing n. If you just want to create a single partition on your drive, accept all the defaults by pressing Enter on each prompt. This will leave you with a single partition that will take up all space on the drive.
  • Back in the main menu, type t to change the partition type. Press L to see all partitions types. Here we are going to choose 7 (HPFS/NTFS/exFAT). “The partition type […] is a byte value intended to specify the file system the partition contains and/or to flag special access methods used to access these partitions” (source). Linux does not care about the partition type, but Windows does, so we have to change it.
  • Press w to write your changes to the disk and exit fdisk.

Format partition with NTFS

Now we create the actual NTFS file system on the drive:

$ sudo mkfs.ntfs -Q -L label /dev/sdX1

(If you don’t have mkfs.ntfs installed, use your distro’s package manager to install it (on Arch Linux it’s in a package called ntfs-3g)).

Breakdown:

  • -Q is the same as --quick, -f or --fast. This will perfom a quick format, meaning that it will skip both zeroing of the volume and and bad sector checking. So obviously, leave this option out if you want the volume to be zeroed or you want error checking. Depending on the size of your partition, this might take quite a while.
  • -L is the same as --label: it’s the identifier you’ll see in Windows Explorer when your drive is connected.
  • dev/sdX1: change the X to the actual letter of your drive we found earlier in this tutorial. You always format a partition, not a drive, so make sure that you put the correct number of the partition you want formatted at the end.

Create Arch Linux Live USB

Table of Contents

Download image and PGP signature

From https://www.archlinux.org/download/. The preferred option is to download the image using bittorrent, so as to unburden the Arch servers.

Verify downloaded image

$ gpg --keyserver pgp.mit.edu                       \
        --keyserver-options auto-key-retrieve       \
        --verify archlinux-version-x86_64.iso.sig

If this disk is being created on an Arch Linux system, you could also invoke:

$ pacman-key -v archlinux-version-x86_64.iso.sig

The -v switch is short for --verify.

Insert USB drive and check the device name

$ sudo fdisk -l

The -l is short for --list, and will display the device names and partition tables.

Output will look like:

Disk /dev/sdb: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Disk model: CT2000MX500SSD1
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x117d68c1

Device     Boot Start        End    Sectors  Size Id Type
/dev/sdb1        2048 3907029167 3907027120  1.8T 83 Linux

Check the output and find the device name of the USB (for instance /dev/sdc). Make sure this device is not mounted, otherwise the next command will fail. Also make sure you note the device name, and not a partition (indicated by a numeral at the end: /dev/sdc1, for example).

Copy Arch Linux image to USB drive

$ sudo dd if=archlinux-2019-01-01-x86_64.iso    \
        of=/dev/sdX                             \
        bs=64K                                  \
        oflag=sync                              \
        status=progess

Breakdown:

  • if indicates the input file (the .iso of the live Linux distro).
  • of, likewise, points to the output file, which is a device in this case. Note that /dev/sdX needs to be replaced with the device name we found in the previous step.
  • bs=64K indicates the block size, which means that dd will read and write up to 64K bytes at a time. The default is 512 bytes. It really depends what the optimal block size is, but several sources indicate that 64K is a good bet on somewhat modern to modern hardware.
  • oflag stands for “output flag”. The sync flag will make sure that all data is written to the USB stick when the dd command exits, so it will be safe to remove the USB stick.
  • status=progress indicates the level of information that is printed during file transfer. progress shows periodic transfer statistics.

Notice that the device does not need to be partitioned or empty before this operation. When dd writes to a device rather than a partition, all data on the drive – including partitions – will be erased anyway.

Spring Basics: @Conditional Bean Wiring

Table of Contents

A Use Case for Conditional Bean Wiring

Suppose we want to enable caching for our web application. We are interested to find out whether this helps our application or whether the overhead will so big that it actually slows our application down. We decide we want to put the new functionality behind a feature toggle. We add a new property to our application called app.caching.enabled=false. When we are ready to enable the caching, we change the property’s value to true and we are in business. When the results disappoint, we can easily revert the property’s value to false.

@Conditional Introduction

The @Conditional annotation can be used on any type or method that declares a bean:

@Conditional(SomeCondition.class)
@Bean
public SomeBean someBean() {
    return new SomeBean();
}

@Conditional takes a mandatory class that implements the functional interface Condition. Condition defines a single method matches that returns a boolean. The method decides whether the bean should be loaded into the Spring context or whether it should be ignored:

public SomeCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        /* make decision based on context and metadata */
    }
}

A @Conditional @Configuration

When @Conditional is applied to a class which is also annotated with @Configuration, then all of the @Bean methods, @Import, @ComponentScan and other annotations will be subject to the condition. This means that when the condition evaluates to false, all of the configuration defined in that class will be ignored.

Since creating a cache carries costs with it (even an unused cache reserves space on the heap for its initial size), this is exactly what we want in our situation.

@Configuration
@Conditional(CacheCondition.class)
public class CacheConfig {

    /* ... define cache manager and caches here ... */

    public static CacheCondition implements ConfigurationCondition {
        public ConfigurationPhase getConfigurationPhase() {
            return ConfigurationPhase.PARSE_CONFIGURATION;
        }

        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().getRequiredProperty("app.caching.enabled", Boolean.class);
        }
    }
}

Since we are dealing with a conditional configuration instead of a regular bean, the condition class implements ConfigurationCondition instead of Condition. The ConfigurationCondition makes us implement another method that specifies at which point the condition should be evaluated. Normally, this ConfigurationPhase is set to REGISTER_BEAN, which means it checks the condition when adding a regular bean. In this case, we want it set to PARSE_CONFIGURATION, which makes Spring evaluate the condition at the moment the configuration class is parsed. If the condition does not match at that moment, the @Configuration class will not be added to the context.

Dependencies

The only dependency is on spring-context:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.1.RELEASE</version>
</dependency>

Sample Project

A sample project can be found on GitLab.

Spring Basics: Dynamically Inject Values With Spring’s @Value

Table of Contents

If we do not want to hard-code values into our source code, we can use properties files. With the @Value annotation, Spring gives us an easy means to get properties from properties files and inject them into our code.

Dependencies

This post was written with Spring 5.0.5.RELEASE and Java 1.8.0_181.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

Inject Scalars

Let’s say we have the following key-value pairs in a file app.properties:

app.string.property=hello
app.integer.property=987
app.floating.point.property=3.14159
app.boolean.property=false

To get access to these properties, we declare an application configuration in Java:

@Configuration
@ComponentScan
@PropertySource("app.properties")
public class AppConfig {}

The @PropertySource adds a property source to Spring’s Environment. Here, the properties file is placed in the root of the classpath (and since I am using Maven default paths, that would be src/main/resources.

package com.relentlesscoding.wirebeans;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class HabitTest {

    @Value("${app.string.property}")
    private String stringProperty;

    @Value("${app.integer.property}")
    private int integerProperty;

    @Value("${app.floating.point.property}")
    private float floatingPointProperty;

    @Value("${app.boolean.property}")
    private boolean booleanProperty;

    @Test
    public void stringProperty() {
        assertThat(stringProperty, is("hello"));
    }

    @Test
    public void integerProperty() {
        assertThat(integerProperty, is(987));
    }

    @Test
    public void floatingPointProperty() {
        assertThat(floatingPointProperty, is(3.14159F));
    }

    @Test
    public void booleanProperty(){
        assertThat(booleanProperty, is(false));
    }
}

Injecting Complex Values

Let’s say we also have collections of values in our properties file:

app.collection.strings.property=one, two, three
app.collection.floats.property=1.2, 3.4, 5.6
app.collection.dates.property=2018-09-30T10:00:00, 2018-09-29T11:00:00, 2018-09-28T12:00:00

By default, Spring won’t be able to interpret Lists of values. The best we can do, by default, is getting an array of Strings:

@Value("${app.collection.strings.property}")
private String[] stringArrayProperty;

@Test
public void stringsArrayProperty() {
    assertArrayEquals(new String[]{"one", "two", "three"}, stringArrayProperty);
}

Declare a ConversionService to Inject Collections And Other Complex Types

To convert properties to other types than strings, we need to enable Spring’s ConversionService.

@Bean
public static ConversionService conversionService() {
    return new DefaultFormattingConversionService();
}

We instantiate DefaultFormattingConversionService, which is “configured by default with converters and formatters appropriate for most applications”. That means that it can convert comma-separated strings to common, generic collection types, and can convert strings to dates, currencies and TimeZones, for example.

Notice that the method is declared static. ConversionService is of type BeanFactoryPostProcessor and must be instantiated very early in the Spring container lifecycle, so that its services are available when processing of annotations such as @Autowired and @Value are done. By declaring the method static, the ConversionService can be invoked without instantiating the enclosing @Configuration class. Therefore, we can use @Value (and other annotations) that make use of this converter in the same class, without running into the trouble that ConversionService is not yet instantiated.

To learn more about bean instantiation, read the part under “BeanFactoryPostProcessor-returning @Bean methods”. Also, this answer on StackOverflow is very clarifying.

@Test
public void floatArrayProperty() {
    assertArrayEquals(new float[]{1.2F, 3.4F, 5.6F}, floatArrayProperty, 0.01F);
}

To convert dates from a properties string to actual date objects we need an extra step: @DateTimeFormat. This annotation indicates the format of the date to Spring. In this case, we format our property strings to conform to ISO-8601 or DateTimeFormat.ISO.DATE_TIME:

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@Value("${app.collection.dates.property}")
private List<LocalDate> listOfDatesProperty;

@Test
public void listOfDatesProperty() {
    assertThat(listOfDatesProperty.size(), is(3));
    assertEquals(LocalDate.parse("2018-09-30T10:00:00", DateTimeFormatter.ISO_DATE_TIME), listOfDatesProperty.get(0));
}

Thanks to our ConversionService, we can now convert not only to arrays, but also to collections.

Inject Maps With Spring’s @Value

If we throw in a Spring Expression Language (SpEL) expression, we can even have dictionaries in our properties and convert them to Maps:

app.collection.map.string.to.integer={one:"1", two:"2", three:"3"}
@Value("#{${app.collection.map.string.to.integer}}")
private Map<String, Integer> mapStringToInteger;

@Test
public void mapProperty() {
    assertThat(mapStringToInteger.size(), is(3));
    assertEquals(new Integer(1), mapStringToInteger.get("one"));
    assertEquals(new Integer(2), mapStringToInteger.get("two"));
    assertEquals(new Integer(3), mapStringToInteger.get("three"));
}

Notice the #{...} that delimits the SpEL expression. It evaluates the string that comes from the properties files and parses it to a Map. To understand how this works, let’s have a look at what a literal map in a SpEL expression would look like:

@Value("#{{1: 'Catch-22', 2: '1984', 3: 'Pride and Prejudice'}}")
private Map<Integer, String> books;

A literal map in a SpEL expression is delimited by braces {key: 'value', ...}. This is exactly what we had in our properties file.

Spring Basics: XML Setter Injection With Custom Method Names

In a previous blog post we ended up with the following XML-based configuration:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="firstStreak" class="com.relentlesscoding.wirebeans.PositiveStreak">
        <constructor-arg ref="startTime"/>
    </bean>
    <bean id="secondStreak" class="com.relentlesscoding.wirebeans.PositiveStreak">
        <constructor-arg ref="startTime"/>
    </bean>

    <util:list id="myRunningStreaks">
        <ref bean="firstStreak"/>
        <ref bean="secondStreak"/>
    </util:list>

    <bean id="running" class="com.relentlesscoding.wirebeans.Running">
        <property name="streaks" ref="myRunningStreaks"/>
    </bean>

</beans>

The complete code can be found on GitLab.

To recap, we instantiate a bean of type LocalDate by invoking its now() static method. We inject this bean into two PositiveStreak beans using constructor injection. We reference the LocalDate bean by its id, startTime. Next, we create a bean that is a list of PositiveStreaks using the util namespace. We then inject this list into a Habit class called Running using setter injection.

For setter injection to work from XML, the setter method needs to follow Java bean conventions. This means that there should be setter method called set<PropertyName>, where the important part is that the method start with set. The name of the property itself can be something completely different from the field it is setting, Spring does not care. For example, the following would work without a hitch:

class Running implements Habit {
    private List<Streak> myStreakList;

    public void setStreaks(List<Streak> aListOfStreaks) {
        this.myStreakList = aListOfStreaks;
    }
}
<bean class="com.relentlesscoding.wirebeans.Running">
    <property name="streaks" ref="myRunningStreaks" />
</bean>

The only important thing is that the name attribute of the property element corresponds to the Property part of setProperty setter method in Java. To reiterate: The name of the field that is being set by the mutator method can be something completely different from the name attribute of the property element.

But sometimes we want to be creative with our method names if that makes the code more readable, or maybe we are dealing with code that we cannot change. If we end up with a mutator method that does not start with set, you are now in a position to appreciate that Spring will not find this method and throws a BeanCreationException.

Handling Mutators With a Non-Standard Names

On StackOverflow a solution was proposed that uses a MethodInvokingFactoryBean. But since we are invoking a method that does not return a result, the documentation recommends we use MethodInvokingBean instead.

Suppose we have the follow setter in place:

class Running implements Habit {
    private List<Streak> myStreakList;

    public void replaceStreaks(List<Streak> aListOfStreaks) {
        this.myStreakList = aListOfStreaks;
    }
}

We could leverage a MethodInvokingBean like so:

<bean id="running" class="com.relentlesscoding.wirebeans.Running">

<bean id="caller" class="org.springframework.beans.factory.config.MethodInvokingBean">
    <property name="targetObject" ref="running"/>
    <property name="targetMethod" value="replaceStreaks"/>
    <property name="arguments" ref="myRunningStreaks"/>
</bean>

(Notice that we actually use setter injection on the MethodInvokingBean by specifying properties on it.) The targetObject attribute specifies on which instance a targetMethod should be invoked. We can specify our custom mutator name, and pass a reference to our arguments.

This is verbose, so think carefully before you violate the Java bean naming convention. Consider using a facade if the code is not under your control. Alternatively, Java-based Spring configuration with the @Autowired annotation will work on a method with any name.

Spring Basics: Wiring Beans with XML Configuration

If you have to work with legacy Spring applications, chances are you will have know how XML-based configuration works. Although Java configuration is preferred for new applications, sometimes you just don’t have a choice.

The Code

You can find the code from this blog post on GitLab.

Dependencies

The only dependency you need to get a Spring container running is spring-context. Add in Maven:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

Declaring Beans in XML

The following class will become a bean:

package com.relentlesscoding.wirebeans;

import java.util.List;

public class Running implements Habit {
    private final String name = "Running";
    private final String description = "Run 10 km every day";
    private List<Streak> streaks;

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public List<Streak> getStreaks() {
        return streaks;
    }

    public void setStreaks(List<Streak> streaks) {
        this.streaks = streaks;
    }

    public void addStreak(Streak streak) {
        streaks.add(streak);
    }
}

Create an XML file, give it any name (I would call it applicationContext.xml) and place it in your src/main/resources.

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="running" class="com.relentlesscoding.wirebeans.Running"/>
</beans>

This would wire a bean with the id running that is of type Running (which is a Habit). You can see why this is much more of a hassle to set up than using a simple @Component annotation on a class or a @Bean annotation in a @Configuration class. Those XML namespaces are nasty, but luckily most IDEs will help you with them.

Injecting Beans

To inject dependencies, we have two choices:

  • Constructor injection
  • Setter injection

Unlike with Java configuration, we cannot insert into fields when using XML-based configuration.

Constructor Injection

Suppose we want to insert one bean into another bean, for instance a HabitRepository that persists habits to the database into a HabitService. By using the <constructor-arg /> element and the ref property, we can accomplish this:

<bean id="habitRepository" class="com.relentlesscoding.wirebeans.HabitRepository" />

<bean id="habitService" class="com.relentlesscoding.wirebeans.HabitService">
    <constructor-arg ref="habitRepository" />
</bean>

If we wanted to pass more arguments to the HabitService constructor, we must keep on eye on the order: it must be the same as the order in which they are declared in the class.

To ease working with constructor arguments and as a way to curtail the verbosity of the XML configuration, Spring offers the c XML namespace to help wire beans without the need to create a sub-element <constructor-arg />:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="currentTime" class="java.time.LocalDate" factory-method="now" />

    <bean id="streak"
        class="com.relentlesscoding.wirebeans.PositiveStreak"
        c:startTime-ref="currentTime" />

We define a bean of type java.time.LocalDate and we use the static factory method now() to get an instance of it. We then use the c namespace to pass it to the constructor of our PositiveStreak bean. c:startTime-ref="currentTime" should be read as: pass the reference to the bean with id currentTime to the constructor argument that has the name startTime.

So we can reference constructor arguments by name. We can also reference them by position. c:_0-ref="currentTime" would do the exact same thing. XML does not allow a digit as the first character of an attribute, so we have to use an underscore. If there is only a single argument to the constructor, we can even use the shorthand c:_-ref="currentTime". I would not want to promote this as readable, but it’s good to know it exists and might be used in the wild.

Read more about the c namespace here.

Setter Injection

To use setter injection with XML-based configuration, you use the <property> element. If you look back at the Running class above, you see it has a method setStreak that takes a List<Streak>:

<bean id="startTime" class="java.time.LocalDate" factory-method="now" />

<bean id="streak"
    class="com.relentlesscoding.wirebeans.PositiveStreak"
    c:_0-ref="startTime" />

<bean id="running" class="com.relentlesscoding.wirebeans.Running">
    <property name="streaks">
        <list>
            <ref bean="streak" />
        </list>
    </property>
</bean>

The <property> element has an attribute name that refers to the field name of the bean being set. In the current case, class Running has a field named streaks. As a child element of <property> we define a list of Streak references.

For a list of literal String values, this would have looked like:

<property name="listOfStrings">
    <list>
        <value>string value 1</value>
        <value>string value 1</value>
        <value><null/></value>
    </list>
</property>

The list is wired with literal Strings and even a literal null.

Spring also provides the p namespace to make this more convenient (less verbose):

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="streak"
        class="com.relentlesscoding.wirebeans.PositiveStreak"
        c:_0-ref="startTime" />

    <bean id="running"
        class="com.relentlesscoding.wirebeans.Running"
        p:streaks-ref="streak" />
</beans>

The usage of the p namespace is a lot like that of the c namespace. In this case, p:streaks-ref="streak" tells spring to wire a property named streaks with the bean that is referenced by the id streak. Now, the property streaks takes a List. If we pass only a single element to that list, the current syntax works and Spring will happily insert the single reference to streak into a List for us and pass that to the setter method. If we want to pass more than one element in a list, however, we have to create the list separately first, and then pass the id of that reference to the p property:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="startTime" class="java.time.LocalDate" factory-method="now"/>

    <bean id="firstStreak" class="com.relentlesscoding.wirebeans.PositiveStreak" c:_0-ref="startTime"/>
    <bean id="secondStreak" class="com.relentlesscoding.wirebeans.PositiveStreak" c:_0-ref="startTime"/>

    <util:list id="myRunningStreak">
        <ref bean="firstStreak"/>
        <ref bean="secondStreak"/>
    </util:list>

    <bean id="running" class="com.relentlesscoding.wirebeans.Running" p:streaks-ref="myRunningStreak"/>
</beans>

We need to add the util namespace and the location of the util schema definition to get this to work. You see that the XML becomes quite verbose the more you try to do with it. The util namespace allows us to create collections of literal values or beans. These collections can then be referenced by their id.

More information:

Taking the App for a Test Ride

package com.relentlesscoding.wirebeans;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class HabitTest {

    @Autowired
    Habit runningHabit;

    @Test
    public void runningHabitIsNotNull() {
        Assert.assertNotNull(runningHabit);
    }

    @Test
    public void runningHabitHasSingleStreak() {
        Assert.assertEquals(2, runningHabit.getStreaks().size());
    }
}

To run integration tests where the Spring context is available, you need the following dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.5.RELEASE</version>
    <scope>test</scope>
</dependency>

spring-test contains the SpringRunner JUnit runner, and the @ContextConfiguration that will tell Spring where to look for the application context that contains the beans that need to be wired. In this case, we tell it to look at the applicationContext.xml that we put in src/main/resources, so we can reference it by looking at the root of our classpath with the attribute locations = "classpath:applicationContext.xml".