Author Archives: Bing Bong

Spring AOP

Aspect-orientated programming is used to address cross-cutting concerns that lead to code scattering (boiler plate code by spreading the same concern across your application) and/or code tangling (neglection of single responsibility by coupling different concers). Examples for cross-cutting concerns are generic functionalities, such as logging or security checks before method execution.

Spring offers of AspectJ or Spring AOP. For the latter, normal Java-Code is written AspectJ on the other is more powerful (for example, aspects can only be woven around visible methods of Spring beans with Spring AOP). AspectJ uses byte code modification to weave in the aspects, Spring AOP relies on dynamic proxies.

Because of the proxy usage a method call from within the same class/interface will NOT trigger the advice.

AOP uses the concepts of

  • JoinPoint: What is affected: The place in your program where the concern will be applied to, e.g. the method call
  • Pointcut: Where is it applied: Expression to match application code for JoinPoints
  • Advice: What is the aspect’s concern: Code that is executed at a JoinPoint
  • AdviceType: When is the advice applied, @Before, @AfterThrowing, @Around, @AfterReturning, @After etc.
  • Aspect: Component to encapsulate pointcuts and advice

Implementing an aspect

To use AOP you need to have an aspect and use it as a bean. Here’s an example with a separate configuration:

Example aspect:

@Aspect
@Component
public class GenericLogger {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(GenericLogger.class);
    
    @Before("execution(* add*(..))")
    public void debugAddCall(JoinPoint joinPoint) {
        String joinPointName = joinPoint.getSignature().getName();
        Object joinPointArg0 = joinPoint.getArgs()[0];
        String targetType = joinPoint.getTarget().getClass().getSimpleName();    //not very practiable here, just to show how to access the target
        LOGGER.debug("Method {} about to be called on type {} with argument {}", joinPointName, targetType, joinPointArg0);
    }
}

Aspect configuration:

@ComponentScan("ch.pma.useradmin.logging") //package where to find the aspect-bean(s)
@EnableAspectJAutoProxy
public class LoggingConfiguration {
 
}

You then only need to the configuration into your main-configuration-class:

@Import(LoggingConfiguration.class)

The same in XML:

<aop:aspectj-autoproxy />
<context:component-scan base-package="..."/>

Exceptions

If you use @Before and the advice itself throws an exception, the target will not be called.

@After will be called regardless of whether the target threw an exception or not.

@AfterReturning, @AfterThrowing and @Around

If you use @AfterReturning, you can access the returned value by defining it in the annotation and as an argument:

@AfterReturning(value="execution(...)", returning="returnedObject")
public void debugReturnedObject(ReturnedObjectType returnedObject) {
    ...
}

With @AfterThrowing, the case for a thrown exception is similar:

@AfterThrowing(value="execution(...)", throwing="exception")
public void logException(ExceptionType exception) {
    ...
}

With the @Around advice, you pass a

ProceedingJoinPoint

as an argument to your advice on which you call

.proceed()

to call the method (or decide to skip it by not calling proceed()).

Pointcut expressions

An expression consists of a designator (normally “execution”) and a combination of annotation, return type, package, type, method and params to match.

You can use wildcards such as “*”, “**”, or “..”. Operators such as “||”, “&&” and “!” are supported as well.

Pointcut expressions might also match annotations:

@After("execution(@ch.pma.useradmin.annotation.ServiceMethod * *(..))")
public void debugServiceMethodCall() {
    LOGGER.debug("Service-method was called");
}

matches any method annotated with

@ServiceMethod

Alternatively, there is a designator for annotations:

@Before("execution(...) &amp;&amp; @annotation(serviceMethod)")
public void doSomething(ServiceMethod serviceMethod) {
    ...
}

The expression can also provide typesafe access to target, arguments and/or the proxy-object.

All the types do have to match or the advice will be skipped:

@Before("execution(void *.RepositoryService.*(java.util.Map)) &amp;&amp; target(instance) &amp;&amp; args(map) &amp;&amp; this(proxy)")
public void doSomething(RepositoryService instance, Map map, RepositoryService proxy)(
    ...
}

Remember that for the proxy, an interface will be implemented or a class extended, therefore it is possible to narrow the execution via definition of the type to be proxied.

@Pointcut

With the

@Pointcut

annotation you can break complex expressions into separate ones and reference them in the advices’ expression:

@Pointcut("execution(* package1.*.*(..))")
public void pointcut1() {}
 
@Pointcut("execution(* package2.*.*(..))")
public void pointcut2() {}
 
@Before("pointcut1() || pointcut2()")    //you could even fully-qualify your pointcut(s) here
public void doSomething(JoinPoint joinPoint) {
        LOGGER.debug("Method to be called on {}", joinPoint.getSignature().getName());
}

The expression can also provide typesafe access to target and arguments. If the types do not match, the advice will be skipped:

@Before("execution(void *.RepositoryService.*(java.util.Map)) &amp;&amp; target(instance) &amp;&amp; args(map) &amp;&amp; this(proxy)")
    public void doSomething(RepositoryService instance, Map map, RepositoryService proxy)(
        ...
    }

Integration tests with Spring

Unit tests of your project created with Spring, you should not depend on Spring, as unit tests must not depend on external dependencies and Spring is an external dependency. These dependencies should be stubbed or mocked instead.

However, Spring provides support for integration testing with configurations, profiles and databases. These support-classes are located in spring-test.jar and are used in combination with JUnit.

Setup

@RunWith(SpringJUnit4ClassRunner.class)

annotation on your testclass creates an application context which is shared for all test methods.

If a test method modifies beans in the application context it can be annotated with

@DirtiesContext

to clean the context after the test execution.

Configurations

To reference a configuration for the tests, the testclass can be annotated with

@ConxtextConfiguration(classes=TestConfig.class)

With that in place, you can inject the bean to be tested into your test class using

@Autowired

Example

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=TestConfig.class)
public class MyServiceTest {
 
    @Autowired
    private MyService myService; //bean to be tested
 
    @Test
    public void testMyService() {
        myService.doSomething();   
    }
}

@ContextConfiguration could also be supplied with a string array to reference XML configurations. Without any argument, it defaults to

[classname]-context.xml

in the same package.

As a third option, you can add a test-specific configuration directly in the testclass by defining an static inner class in the test class and annotate it with

@Configuration

Profiles

Testing with profiles can be done by annotating the test class with

@ActiveProfiles({"profile_1","profile_2"})

Beans associated to one of the defined profiles and those not associated to any profile,
will be loaded automatically.

Testing with databases

When you run tests against an in-memory-database you can use

@Sql

ensure its proper state or to insert some testrecords.

@Sql can be supplied with string arguments referencing sql-scripts.

If the annotation decorates a class, the script(s) run before every test method but it can also decorate a single test method.

Also, multiple @Sql annotations can be used and there is a possibility, to set an

executionPhase

e.g. to run a specific script as cleanup after a certain method.

If no string argument is defined with the annotation, the script will be referenced as

[classname].[methodname].sql

Defining

config=@SqlConfig(...)

as argument of @Sql gives you a whole lot of other options to control the scripts, e.g. if the test should fail, if the execution of the script fails.

In-memory databases

Create a DataSource bean of an

EmbeddedDatabaseBuilder

where you define a name, a type (HSQL, H2 or Derby) and can add several scripts with

.addScript("classpath:testdb-schema.sql")

to set it up. Finally, call

.build();

The XML-equivalent is

<jdbc:embedded-database id="..." type="...">
    <jdbc:script location="..." />
</jdbc:embedded-database>

Example

Testclass:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={UseradminConfiguration.class, TestRepositoryConfiguration.class})
public class UserServiceTest {
 
    @Autowired
    private UserService userService;
    
    @Test
    @Sql(scripts="classpath:testdata.sql", executionPhase=ExecutionPhase.BEFORE_TEST_METHOD)
    public void testUserRetrieval() {
        User testUser = userService.getUserById(1);
        assertTrue("test".equals(testUser.getFirstName()) && "user".equals(testUser.getLastName()));
    }
}

Testconfiguration:

(Depending on the implementation of service and repository, the only bean needed could be the data-source).

@Configuration
public class TestRepositoryConfiguration {
 
    @Bean(name = "dataSource")
    public DataSource dataSource() {
 
        EmbeddedDatabaseBuilder dataSource = new EmbeddedDatabaseBuilder();
        dataSource.setType(EmbeddedDatabaseType.H2);
        dataSource.addScript("classpath:schema.sql");
        return dataSource.build();
    }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException, PropertyVetoException {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource());
        emf.setJpaProperties(new Properties());
        emf.setJpaVendorAdapter(jpaAdapter());
        emf.setPackagesToScan("ch.pma.useradmin.entities");
        return emf;
    }
 
    private JpaVendorAdapter jpaAdapter() {
        return new HibernateJpaVendorAdapter();
    }
    
    @Bean
    public JpaTransactionManager transactionManager() {
        return new JpaTransactionManager();
    }
}

schema.sql

DROP TABLE IF EXISTS USER;
CREATE TABLE USER (id INTEGER IDENTITY PRIMARY KEY, first_name VARCHAR(50), last_name VARCHAR(50) NOT NULL, STATUS INT(11), ROLE VARCHAR(50));

testdata.sql

INSERT INTO USER(first_name, last_name, STATUS, ROLE) VALUES('test', 'user', 1, 'admin');

Using an existing test database

You need a

DataSourceInitalizer

where you set the dataSource pointing to the database and a

DatabasePopulator

(e.g. ResourceDatabasePopulator) which you provide with the paths to the initialization scripts.
The same in XML is more compact:

<jdbc:initialize-database data-source="...">
    <jdbc:script location="..." />
<jdbc:initialize>

Spring Basics

Disclaimer

You are not reading a complete reference, the posts are more about a simple understanding and getting something to work with.

Most examples use Java config rather than XML or annotation-based configuration.

What is Spring

Spring is

  • a Framework
  • a Container
  • open source

The framework consists of many subprojects to simplify working with lower-level technologies. Get an overview here: http://spring.io/projects

The projects to choose from may be overwhelming in the beginning, but simply remember this: Whenever you have a (Java-)programming problem of which you may think that somebody could have solved it already, search for it in the Spring-world and safe quite some time maybe.

Source code is available here: https://github.com/spring-projects/spring-framework

Binaries are available here: http://mvnrepository.com/artifact/org.springframework

As a container, it servers as a lifecycle manager by

  • instantiating your application objects (beans)
  • injecting their dependencies, so you do not have to care about them finding and connecting to each other

Configuration

Spring is configurable and focuses on programming against interfaces. Therefore, the complexity of the implementation can be concealed and implementations can be easily swapped out, e.g. for testing. Your objects managed by Spring are so called Spring-Beans.

The central part of your spring-application, the configuration, can be set up in different ways:

  • Using XML, the traditional way
  • Annotation based (required for Spring MVC)
  • by Java config, meaning the configuration is also a bean derived from a Java-class

Comparison between Java config and annotations

Java config pros:
  • Is centralized in one (or a few) places
  • Strong type checking enforced by compiler and IDE
  • Can be used for all classes
Java config cons:
  • More verbose than annotations
Annotation pros:
  • Frequently changes of beans made easy
  • the class as single place to edit
  • rapid development
Annotation cons:
  • Configuration spread across your classes (more maintenance/debugging)
  • Only applicable for your own code
  • Bad separation of concerns as configuration and code are merged

The configuration contains instructions on how Spring sets up its application-context which creates your fully configured application system.

Java config example

@Configuration
@ComponentScan("ch.pma.myapp")
public class MyConfiguration {
 
    @Bean(name="myService")
    public MyService getMyService() {        
        return new MyServiceImpl();
    }
 
    @Bean(name="myRepository")
    public MyRepository getMyRepository() {       
        return new MyRepositoryImpl();
    }
}

@ComponentScan allows you to use annotation-based configuration on classes, effectively combining the two methods of Java config and annotation-based configuration. For example, we can define a controller-bean using the @Controller-annotation, turning it into a bean available in the application context:

@Controller
public class MyController {
 
    private MyService myService;
 
    @Autowired
    public void setMyService(MyService myService) {       
        this.myService = myService;
    }
 
    public User getUserById(int id) {
        return myService.getUserById(id);
    }
}

@Controller, normally used in a web-environment for example in combination with @RequestMapping(s), is a sub-annotation of

@Component

You could also use one of the other stereotype sub-annotations

@Repository (e.g. for exception-translation)
or 
@Service

for the other beans, the effect in this example is the same. All beans, whether they are defined in an XML, based on annotated classes and picked up by the component-scan or created in the configuration, will be fully initialized available in the application-context.

You can set a bean-name with the annotation, if not set, the name will be the class-name in camelCase.

When you enable the component-scan, be sure to define base-package(s) as your whole classpath will be scanned otherwise.

Bean uniqueness

When you annotate two classes of the same type as beans, you need to provide an ID, which you can refer to via @Qualifier to wire the correct bean:

@Component("prodRepository")
public class JdbcRepository implements MyRepository {}
@Component("devRepository")
public class JpaRepository implements MyRepository {}
@Service
public class MyServiceImpl implements MyService {
    @Autowired   
    @Qualifier("devRepository")    
    MyRepository myRepository;
}

If no unique bean can be found by type and no @Qualifier is to be used, Spring tries to find a matching bean by name = bean-id.

These examples will look for a bean with id “sampleBean”:

@Autowired
private MyBean sampleBean;
@Autowired
public void setSampleBean(MyBean myBean) {
    ...
}
@Autowired
public void someValue(MyBean sampleBean) {
    ...
}

Multiple configuration files

You can split your configuration into several classes and combine them in your main-configuration file by using

@Import({Configfile1.class, Configfile2.class})

You could even combine XML-configuration with your configuration-class, using @ImportResource:

@Configuration
@ImportResource({"classpath:ch/pma/application-config.xml", "file:/home/pma/application-config.xml"})@Import(Configfile1.class)public class MyConfig { ... }

A bean reference from another configuration-file can be obtained by using

@Autowired

allowing you to separate your “application” beans from your “infrastructure” beans.

When using @Autowired, a unique dependency of the correct type must exist as long as “(required=false)” is not added to the annotation. With Java 8 and Lambdas, optional autowiring can be defined and used like follows:

@Autowired
Optional<YourService> yourService;
 
public void useService() {
    yourService.ifPresent( s -> {
        //s is the instance of YourService
    });
}

Example

@Configuration
@Import(InfrastructureConfiguration.class)
public class ApplicationConfiguration {
 
    @Autowired
    DataSource dataSource;
 
    @Bean
    public MyRepository myRepository() {
        MyRepositoryImpl myRepository = new MyRepositoryImpl();
        myRepository.setDataSource(dataSource);
        return myRepository;
    }
}
@Configuration
public class InfrastructureConfiguration {
 
    @Bean
    public DataSource getDataSource() {
        ...
    }
}

In general you can use

@Autowired

on a constructor, method or (even on a private) field. Some say, using it on a field is bad practice though (see http://olivergierke.de/2013/11/why-field-injection-is-evil/).

It is not illegal to define the same bean more than once (hence in different configurations), you will get the last bean Spring sees defined.

ApplicationContext

Spring application contexts can be bootstrapped in any environment, you can even use more than one context, e.g. one for the repository-domain of your application and separate ones for different web-endpoints.

Use your configuration when setting up the application context and retrieve beans from it to work with.

Example

public class MyApp{
 
    private ApplicationContext applicationContext;
 
    public static void main(String[] args) {
 
        new MyApp();
    }
 
    public MyApp() {
 
        initApplicationContext();
        MyController myController = applicationContext.getBean(MyController.class);
        myController.getUserById(1);
        closeApplicationContext();
    }
 
    private void closeApplicationContext() {
        ((ConfigurableApplicationContext) applicationContext).close();
    }
 
    private void initApplicationContext() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
        this.applicationContext = applicationContext;
    }
}

Bean scope

Possible scopes are

  • singleton
  • prototype (instantiates a new bean every time the bean is referenced)
  • request (foreseen for usage in web-environments)
  • session (foreseen for usage in web-environments)
  • custom (define your own name and rules for this scope)

Singleton is the default scope, meaning that multiple calls to

applicationContext.getBean("...")

always returns the same instance. For using another scope, the bean has to be annotated with

@Scope("[desired_scope]")

Bean lifecycle in an application context

Creation:

In general:

  • Bean definitions loaded
  • Post process bean definitions (BeanFactoryPostProcessor; e.g. replacing property placeholders with their actual value by a PropertySourcesPlaceholderConfigurer. These beans must be defined as static methods, to ensure their early presence.)

For each bean:

  • Instantiate bean (eagerly by default, using lazy is not recommended)
  • Populate properties (dependency injection)
  • setters for bean-factory and application-context
  • BeanPostProcessor postProcessBeforeInitialization
  • afterPropertiesSet()
  • custom init-method
  • post-construct or BeanPostProcessor postProcessAfterInitialization, depending on the order-property

ApplicationContexts autodetect BeanPostProcessor beans in their bean definitions and applies them to any beans subsequently created.

BeanPostProcessors are used e.g. for proxying the bean, for example to handle transaction management.

Plain bean factories allow for programmatic registration of post-processors, applying to all beans created through this factory. For standard usage you will not need a BeanFactory though, as the application context extends the BeanFactory.

Destruction:

Is completed when an application context is closed

If available:

  • @PreDestroy or @Bean(destroyMethod=”…”) / destroy-method=”…” (XML)
  • destroy() (if DisposableBean)

Actual destruction of objects will follow when the garbage collection runs for the next time.

External Properties

Getting properties from the Environment

The environment automatically provides access to System properties and Environment variables.

Use Environment explicitly:

@Autowired
public Environment env;
...
env.getProperty("db.url");

or implicitly by using “${…}” placeholders:

@Value("${db.url}") String dbUrl

For undefined values, an alternative value can be provided using a colon:

@Value("${db.connectionLimit:10}")private int connectionLimit;

Property Sources

@PropertySources("[classpath:|file:|http:]/my_props.properties")

is used for referencing other sources but requires a bean PropertySourcesPlaceholderConfigurer-bean:

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

Your property-source path can also contain ${…}-placeholders, which are resolved against existing system properties and environments variables.
This way, you could provide different property-files for different environments like dev, test or prod.

SpEL

Spring expression language can be used to resolve more complex expressions than just property-names.

Examples:

@Value("#{systemProperties['db.url']}") 
String dbUrl;
 
@Bean 
public DataSource dataSource(@Value("#{systemProperties['db.url']}") String url, …) {
    DataSource dataSource = new DataSource();
    dataSource.setUrl(url);
    return dataSource;
}

systemProperties and systemEnvironment are available by default.

It is also possible to access public fields and/or getters of beans:

@Value("#{dataSource.url}") 
String dataSourceUrl;

SpEL also supports the Elvis-operator, to shorten the usage of a ternary operator with a null-check:

ExpressionParser parser = new SpelExpressionParser();
String testName = null;
String actualName = parser.parseExpression("testName ?: 'Unknown'").getValue(String.class);

In general, SpEL is way more powerful than what’s shown in these few examples. Read this: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html for more insight on the topic.

Profiles

Beans can be grouped into profiles by using

 @Profile("[desired_profile_id]")

on the configuration or on the bean.

Beans not grouped by a profile are always active.

Profiles need to be activated to be usable. Ways to do so are:

  • For testing: @ActiveProfiles
  • Web-Application: Setting context-param name spring.profile.active and value to the desired profile(s) in the web.xml
  • System property: -Dspring.profiles.active=profile1,profile2
  • Setting the spring.profiles.active system property programmatically before accessing the application context

Proxying

When using Java config, Spring proxies @Configuration using cglib. It creates a subclass of the

@Configuration
public class MyConfig {
...
}

named

public class MyConfig$$EnhancerByCGLIB$ extends MyConfig {
...
}

When referencing a singleton bean, this class first checks if it already existis in the application-context and returns it if so. Otherwise it calls the super-class to get the bean, stores in the application-context and returns it.

A BeanPostProcessor may wrap any bean with a proxy adding behaviour transparently. For example, your calls to your @Transactional RepositoryService are routed through a TransactionInterceptor who begins and commits (or rolls back) the transaction.

Spring uses JDK and CGLib to set up proxies. By default, all interfaces are proxied using dynamic (JDK) proxies. CGLib, which is included in the Spring .jars, is used when no interface is available as long as the class or method is not declared final.

Therefore, a JDK proxy will implement the interface, while the CGLib proxy will extend the class to be proxied.

Comparison between Java config and XML

Java config XML
Profile
@Profile("dev")
public class DevClass {}
<beans profile="dev">
</beans>

You can nest -tags within the parent-beans-tag to separate beans
into several profiles

Bean ID
@Bean
public MyService myService() {}
//id = methodname

or

@Bean(name="myService") //id = name
public MyService someService(){}
<bean class="ch.pma.myapp.services.MyService" id="myService"/>
Dependency injection
MyService myService = new MyServiceImpl();
myService.setDependency(myDependency());
<bean id="myService">
  <property name="dependency" ref="myDependency"/>
  <!-- implicit reference to setter setDependency(...) -->
</bean>

For some types, properties can be set using

<property name="someProperty" value="..." />
or
<property name="someProperty>
  <value=>...</value>
</property>

instead of ref=””. These types are:

  • Numeric types
  • BigDecimal,
  • boolean: “true”, “false”
  • Date
  • Locale
  • Resource
Constructor injection (unlike for setter-injection, constructor-arguments can not be treated as optional)
MyService myService = new MyServiceImpl(myDependency());
<bean id="myService">
  <constructor-arg ref="myDependency"/>
</bean>

constructor-arg elements can be in any order, to indicate your intended order when passing
ambigous values, use index (starting from 0)

<constructor-arg index="0" value="123">
<constructor-arg index="1" value="some string">

or set the name property, e.g.

name="intValue"

matching the name of the constructor-argument to omit the index.

Import
@Configuration
@Import(Config1.class)
public class MyConfig { ... }
<beans>
  <import resource="config1.xml" />
<beans>

Relative path is used by default. Alternatives are file, classpath, http.

Bean behaviour
Annotations require annotation-driven or the component-scanner to be activated

@PostConstruct
<bean ... init-method="init">
  ...
<beans>
@PreDestroy
<bean ... destroy-method="destroy">
  ...
<beans>
@Scope(...)
<bean ... scope="...">
  ...
<beans>
@Lazy("true")
<bean ... lazy-init="true">
  ...
<beans>
Component scan
@ComponentScan({"ch.pma.myapp.package1",
"ch.pma.myapp.package2"})
<context:component-scan 
base-package="ch.pma.myapp.package1, ch.pma.myapp.package2"/>

XML Namespaces

The default namespace in a Spring configuration file is typically the “beans” namespace:

<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>

Various framework functionality (aop, tx, context, etc.) can be accessed by adding the corresponding predefined namespace. This makes advanced features of Spring easy declarable.

For example,

<code><span class="atn"><beans ...
  xmlns:tx</span><span class="pun">=</span><span class="atv">"http://www.springframework.org/schema/tx"
  ...
  </span><span class="atn">xsi:schemaLocation</span><span class="pun">=</span><span class="atv">"http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd 
  ...">
  ...
  <tx:annotation-driven />
  ...
</beans></span></code>

hides a couple of bean-definitions for enabling the configuration of transactional behavior based on annotations.

Redstone for Beginners – Sorting Machine

André and I are working on a fancy new housing on the survival instance on his server and it’s becoming obvious that we need a sorting-system for all the good stuff we are getting out of the ground.

So I watched this, tried to build it – and failed.

There were comments saying that it would not work with V 1.8.x but I did not believe that.
The major problem was that I did not understand how the components actually work, therefore I could not debug the system.

Having looked at the Minecraft-Wiki, I realized that it is quite easy to understand. I rebuilt it and now it works – with a small restriction (it is a little annoying that it was not pointed out in the video) described on the bottom of this post .

Here is what you want to achieve: Put random items in a box and let them be delivered to another box of your choice. The transport from the original box to the destination is done via hoppers.

Things to know about the hopper:

  • In general, they will suck items out of dispensers (like boxes or other hoppers) placed above of them for as long as they can
  • In general, if their outlet is connected to a device that can store items, they will pass on everything that is put into them until the target is full. If the outlet is not connected to anywhere, they will not pass items on.
  • They possess 5 item slots of their own. If all slots contain items, the hopper will accept further items of the same kind only. The slots are being emptied from left to right.
  • They send a redstone signal if they have items in their slots. The signal strength is based on the percentage of the fill level – it goes up for every 1/14 of filling. To find out what signal strength your hopper is sending, you need to know the max storage capacity, which again is based on the items you put into the hopper.
    E.g. if you put blocks of iron and dirt into the hopper, the max amount of blocks would be 5 x 64. Floor 1/14 of that is 22, so the signal strength would be 0 for 0 blocks total, 1 for 1 – 22 blocks total, 2 for 23 – 45 blocks total and so on. However, if you use eggs, the total capacity is only 5 x 16 as eggs can only be stacked to 16. 1/14 capacity would then be only 5 eggs.
  • If they receive a redstone signal, e.g from a redstone torch underneath, they will block their in- and outlet

You probably see where this is leading to. We want to have one hopper per material we want to sort (placed in the leftmost slot). To achieve that, we need to pre-fill the sorting hoppers. To pre-fill them, we also need to define one item that we never must put into the machine for being sorted – which is dirt in my case.

Hopper setup front view:

Hopper setup side view:

We need to pre-fill the sorting hoppers with the correct amount of blocks, so that one added block will change the generated signal-strength from 1 to 2. Huh, why is that? Because the bottom level hopper which sucks items out of the sorting hopper above and puts them into the box is deactivated by a redstone torch, so that he does not suck out our pre-filling materials.
If the signal strentgh of the sorting hopper changes, we know that we have to activate the bottom-level hopper. This is done by sending a redstone signal to the redstone torch – for as long as the sorting hopper sends signal strength > 1.

Processing the hopper’s signal

For that we’re going to need the comparator; it has three inputs, one output and a switch.

Basically it does this to calculate the output:

w = y > z ? y : z;
out = x >= w ? (A ? x - w : x) : 0;

For the sorting machine we can use the sorting hopper as the only input x, so that the comparator will just pass on the signal received – with unchanged strength.

Next, we want a sticky piston to activate on signal strength 2. It has a redstone block attached which sends a signal to the appropriate redstone torch and deactivating it, while the piston is extended.
We achieve this by putting exactly 2 blocks between the piston and the comparator and connecting them via redstone, because the signal is diminishing by 1 per redstone wire.

Here it is important to not let a wire interfere with others. That’s what the nifty placing of blocks in the area between comparators and pistons is for. On the floor, mostly comparators are used because they will not compromise each other sideways.

Pistons and comparators on the floor:

Non-interfering redstone-wires:

Most probable sources of error if you are facing problems

  • Hoppers and/or comparators are not facing the correct way
  • Redstone wires interfere with each other on their way to the pistons
  • Incorrect amount of pre-filling in the sorting hoppers

Also, for some components the correct order of placement can be kind of important, e.g. if you prefill your sorting hopper and then put the bottom hopper underneath it without having the redstone torch in place already, it will suck your sorting hopper empty.

About the boxes

To put to small boxes next to each other, every second box has to be a Trapped box instead of a normal one.

Final thoughts

This should enable you to not only build the sorting machine as shown in the video but also understand it and its components – giving you a good base for future Minecraft automation projects.

If you try out the machine, you will notice the small drawback I mentioned in the beginning: The bottom hopper will always keep the last item processed, because the redstone torch underneath is reactivated before the hopper has been emptied completely. I thought about the problem and currently found no easy way to fix that.