Skip to content

Commit

Permalink
mapstruct#962 add conversions between Java 8 Stream and the different…
Browse files Browse the repository at this point in the history
… Java Collection and Iterable types
  • Loading branch information
filiphr committed Nov 22, 2016
1 parent f3e489b commit 9eba96b
Show file tree
Hide file tree
Showing 8 changed files with 557 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,29 @@
*/
package org.mapstruct.ap.internal.conversion;

import static org.mapstruct.ap.internal.conversion.ReverseConversion.reverse;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import javax.lang.model.util.Elements;

import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.util.JavaStreamConstants;
import org.mapstruct.ap.internal.util.JavaTimeConstants;
import org.mapstruct.ap.internal.util.JodaTimeConstants;

import static org.mapstruct.ap.internal.conversion.ReverseConversion.reverse;

/**
* Holds built-in {@link ConversionProvider}s such as from {@code int} to {@code String}.
*
Expand Down Expand Up @@ -185,7 +190,7 @@ public Conversions(Elements elementUtils, TypeFactory typeFactory) {

registerJodaConversions();

registerJava8TimeConversions();
registerJava8Conversions();

//misc.
register( Enum.class, String.class, new EnumStringConversion() );
Expand Down Expand Up @@ -216,8 +221,8 @@ private void registerJodaConversions() {
register( JodaTimeConstants.DATE_TIME_FQN, Calendar.class, new JodaDateTimeToCalendarConversion() );
}

private void registerJava8TimeConversions() {
if ( !isJava8TimeAvailable() ) {
private void registerJava8Conversions() {
if ( !isJava8Available() ) {
return;
}

Expand All @@ -232,13 +237,21 @@ private void registerJava8TimeConversions() {
register( JavaTimeConstants.LOCAL_DATE_TIME_FQN, Date.class, new JavaLocalDateTimeToDateConversion() );
register( JavaTimeConstants.LOCAL_DATE_FQN, Date.class, new JavaLocalDateToDateConversion() );

// Java 8 Stream conversion
register( JavaStreamConstants.STREAM_FQN, Iterable.class, new JavaStreamToIterableConversion() );
register( JavaStreamConstants.STREAM_FQN, Collection.class, new JavaStreamToCollectionConversion() );
register( JavaStreamConstants.STREAM_FQN, List.class, new JavaStreamToCollectionConversion() );
register( JavaStreamConstants.STREAM_FQN, Set.class, new JavaStreamToCollectionConversion() );
register( JavaStreamConstants.STREAM_FQN, SortedSet.class, new JavaStreamToCollectionConversion() );
register( JavaStreamConstants.STREAM_FQN, NavigableSet.class, new JavaStreamToCollectionConversion() );

}

private boolean isJodaTimeAvailable() {
return typeFactory.isTypeAvailable( JodaTimeConstants.DATE_TIME_FQN );
}

private boolean isJava8TimeAvailable() {
private boolean isJava8Available() {
return typeFactory.isTypeAvailable( JavaTimeConstants.ZONED_DATE_TIME_FQN );
}

Expand Down Expand Up @@ -352,15 +365,15 @@ public boolean equals(Object obj) {
return false;
}
}
else if ( !sourceType.equals( other.sourceType ) ) {
else if ( !sourceType.erasure().equals( other.sourceType.erasure() ) ) {
return false;
}
if ( targetType == null ) {
if ( other.targetType != null ) {
return false;
}
}
else if ( !targetType.equals( other.targetType ) ) {
else if ( !targetType.erasure().equals( other.targetType.erasure() ) ) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.internal.conversion;

import java.util.Collection;
import java.util.List;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.util.Collections;
import org.mapstruct.ap.internal.util.JavaStreamConstants;

/**
* Conversion between {@link java.util.stream.Stream} and java utils: {@link Set}, {@link java.util.List},
* {@link java.util.Collection}.
*
* @author Filip Hrisafov
*/
public class JavaStreamToCollectionConversion extends SimpleConversion {

@Override
protected String getToExpression(ConversionContext conversionContext) {
return "<SOURCE>.collect( Collectors." + collector( conversionContext ) + " )";
}

private String collector(ConversionContext conversionContext) {
Type targetType = conversionContext.getTargetType();
TypeFactory typeFactory = conversionContext.getTypeFactory();
String collector = "";
// we must do erasure as JDK compiler does not work without it
//TODO is this a bug in the Java compiler or not?
if ( typeFactory.getType( Iterable.class ).isAssignableTo( targetType.erasure() )
|| typeFactory.getType( Collection.class ).isAssignableTo( targetType.erasure() )
|| typeFactory.getType( List.class ).isAssignableTo( targetType.erasure() ) ) {
collector = "toList()";
}
else if ( typeFactory.getType( Set.class ).isAssignableTo( targetType.erasure() ) ) {
collector = "toSet()";
}
else if ( acceptsTreeSet( conversionContext ) ) {
collector = "toCollection( TreeSet::new )";
}

//TODO what if we register wrong. In the end it won't compile, but should we throw an exception?
return collector;
}

@Override
protected String getFromExpression(ConversionContext conversionContext) {
return "<SOURCE>.stream()";
}

private boolean acceptsTreeSet(ConversionContext conversionContext) {
TypeFactory typeFactory = conversionContext.getTypeFactory();
Type targetType = conversionContext.getTargetType();
return typeFactory.getType( SortedSet.class ).isAssignableTo( targetType.erasure() )
|| typeFactory.getType( NavigableSet.class ).isAssignableTo( targetType.erasure() );
}


@Override
protected Set<Type> getToConversionImportTypes(ConversionContext conversionContext) {
Set<Type> types = Collections.asSet(
conversionContext.getTypeFactory().getType( JavaStreamConstants.COLLECTORS_FQN )
);
if ( acceptsTreeSet( conversionContext ) ) {
types.add( conversionContext.getTypeFactory().getType( TreeSet.class ) );
}
return types;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.internal.conversion;

import java.util.Set;

import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.util.Collections;
import org.mapstruct.ap.internal.util.JavaStreamConstants;

/**
* Conversion between {@link java.util.stream.Stream} and java util {@link Iterable}.
*
* @author Filip Hrisafov
*/
public class JavaStreamToIterableConversion extends JavaStreamToCollectionConversion {

@Override
protected String getFromExpression(ConversionContext conversionContext) {
return "StreamSupport.stream( <SOURCE>.spliterator(), false )";
}


@Override
protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) {
return Collections.asSet(
conversionContext.getTypeFactory().getType( JavaStreamConstants.STREAM_SUPPORT_FQN )
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.internal.util;

/**
* Helper holding Java Stream full qualified class names for conversion registration
*
* @author Filip Hrisafov
*/
public final class JavaStreamConstants {

public static final String STREAM_FQN = "java.util.stream.Stream";
public static final String COLLECTORS_FQN = "java.util.stream.Collectors";
public static final String STREAM_SUPPORT_FQN = "java.util.stream.StreamSupport";


private JavaStreamConstants() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.conversion.java8stream;

import java.util.List;
import java.util.stream.Stream;

/**
* @author Filip Hrisafov
*/
public class Source {


private List<Integer> ints;

private Stream<Integer> stream;

private Stream<String> stringStream;

private Stream<String> stringCollection;

private Stream<Integer> integerSet;

private Stream<Integer> integerIterable;

private Stream<Integer> sortedSet;

private Stream<Integer> navigableSet;

public List<Integer> getInts() {
return ints;
}

public void setInts(List<Integer> ints) {
this.ints = ints;
}

public Stream<Integer> getStream() {
return stream;
}

public void setStream(Stream<Integer> stream) {
this.stream = stream;
}

public Stream<String> getStringStream() {
return stringStream;
}

public void setStringStream(Stream<String> stringStream) {
this.stringStream = stringStream;
}

public Stream<String> getStringCollection() {
return stringCollection;
}

public void setStringCollection(Stream<String> stringCollection) {
this.stringCollection = stringCollection;
}

public Stream<Integer> getIntegerSet() {
return integerSet;
}

public void setIntegerSet(Stream<Integer> integerSet) {
this.integerSet = integerSet;
}

public Stream<Integer> getIntegerIterable() {
return integerIterable;
}

public void setIntegerIterable(Stream<Integer> integerIterable) {
this.integerIterable = integerIterable;
}

public Stream<Integer> getSortedSet() {
return sortedSet;
}

public void setSortedSet(Stream<Integer> sortedSet) {
this.sortedSet = sortedSet;
}

public Stream<Integer> getNavigableSet() {
return navigableSet;
}

public void setNavigableSet(Stream<Integer> navigableSet) {
this.navigableSet = navigableSet;
}
}
Loading

0 comments on commit 9eba96b

Please sign in to comment.